2
0
Эх сурвалжийг харах

Set VCards via events, thereby reducing coupling

- Rename `chatRoomOpened` event to `chatRoomViewInitialized`
- Rename `chatBoxInitialized` to `chatBoxViewInitialized` and trigger only for `ChatBoxView` instances.
- New event `headlinesBoxViewInitialized`
- Trigger the `chatBoxInitialized` event when a new `_converse.ChatBox` is opened.
JC Brand 5 жил өмнө
parent
commit
8b6c902c4c

+ 6 - 1
CHANGES.md

@@ -52,9 +52,14 @@
   * `_converse.api.rooms.create`
   * `_converse.api.roomviews.close`
 
+- Changes the events:
+  * The `chatBoxInitialized` event now triggers when a `_converse.ChatBox` (not the view) is opened.
+  * Renamed the old `chatBoxInitialized` to `chatBoxViewInitialized` and trigger only for `ChatBoxView` instances.
+  * Renamed `chatRoomOpened` event to `chatRoomViewInitialized`
+  * The order of certain events have now changed: `statusInitialized` is now triggered after `initialized` and `connected` and `reconnected`.
+
 - `_converse.api.chats.get()` now only returns one-on-one chats, not the control box or headline notifications.
 - The `show_only_online_users` setting has been removed.
-- The order of certain events have now changed: `statusInitialized` is now triggered after `initialized` and `connected` and `reconnected`.
 - `_converse.api.alert.show` is now `_converse.api.show` and instead of taking
   an integer for the `type`, "info", "warn" or "error" should be passed in.
 - The `converse-headline` plugin has been split up into `converse-headlines` and `converse-headlines-view`.

+ 3 - 3
spec/bookmarks.js

@@ -143,8 +143,8 @@
 
 
         it("will be automatically opened if 'autojoin' is set on the bookmark", mock.initConverse(
-            ['rosterGroupsFetched'], {},
-            async function (done, _converse) {
+                ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
 
             await test_utils.waitUntilDiscoConfirmed(
                 _converse, _converse.bare_jid,
@@ -168,7 +168,7 @@
                 'name':  'The Play',
                 'nick': ' Othello'
             });
-            await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
+            await new Promise(resolve => _converse.api.listen.once('chatRoomViewInitialized', resolve));
             expect(_.isUndefined(_converse.chatboxviews.get(jid))).toBeFalsy();
 
             // Check that we don't auto-join if muc_respect_autojoin is false

+ 3 - 3
spec/chatbox.js

@@ -136,7 +136,7 @@
 
                 const message_promise = new Promise(resolve => _converse.api.listen.on('message', resolve));
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
-                await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
+                await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
                 await u.waitUntil(() => message_promise);
                 expect(_converse.chatboxviews.keys().length).toBe(2);
                 done();
@@ -390,7 +390,7 @@
                 await u.waitUntil(() => _converse.chatboxes.length == 7)
                 expect(_converse.chatboxviews.trimChats).toHaveBeenCalled();
                 expect(_converse.chatboxes.length).toEqual(7);
-                expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxInitialized', jasmine.any(Object));
+                expect(_converse.api.trigger).toHaveBeenCalledWith('chatBoxViewInitialized', jasmine.any(Object));
                 await test_utils.closeAllChatBoxes(_converse);
 
                 expect(_converse.chatboxes.length).toEqual(1);
@@ -1427,7 +1427,7 @@
                 await u.waitUntil(() => chatbox.messages.length > 1);
                 expect(select_msgs_indicator().textContent).toBe('2');
                 view.model.maximize();
-                expect(select_msgs_indicator()).toBeUndefined();
+                u.waitUntil(() => typeof select_msgs_indicator() === 'undefined');
                 done();
             }));
 

+ 2 - 2
spec/controlbox.js

@@ -106,8 +106,8 @@
                 expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count').textContent).toBe('2');
                 expect(_converse.rosterview.el.querySelector('.msgs-indicator').textContent).toBe('2');
                 chatview.model.set({'minimized': false});
-                expect(_.isNull(_converse.chatboxviews.el.querySelector('.restore-chat .message-count'))).toBeTruthy();
-                expect(_.isNull(_converse.rosterview.el.querySelector('.msgs-indicator'))).toBeTruthy();
+                expect(_converse.chatboxviews.el.querySelector('.restore-chat .message-count')).toBe(null);
+                await u.waitUntil(() => _converse.rosterview.el.querySelector('.msgs-indicator') === null);
                 done();
             }));
         });

+ 1 - 1
spec/emojis.js

@@ -170,7 +170,7 @@
                         'id': _converse.connection.getUniqueId()
                     }).c('body').t('😇').up()
                     .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
-                await new Promise(resolve => _converse.on('chatBoxInitialized', resolve));
+                await new Promise(resolve => _converse.on('chatBoxViewInitialized', resolve));
                 const view = _converse.api.chatviews.get(sender_jid);
                 await new Promise(resolve => view.once('messageInserted', resolve));
                 const chat_content = view.el.querySelector('.chat-content');

+ 1 - 1
spec/messages.js

@@ -1082,7 +1082,7 @@
                     'id': (new Date()).getTime()
                 }).c('body').t('A message').up()
                 .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
-            await new Promise(resolve => _converse.on('chatBoxInitialized', resolve));
+            await new Promise(resolve => _converse.on('chatBoxViewInitialized', resolve));
             const view = _converse.api.chatviews.get(sender_jid);
             await new Promise(resolve => view.once('messageInserted', resolve));
 

+ 1 - 1
spec/protocol.js

@@ -360,7 +360,7 @@
                 expect(_converse.roster.updateContact).toHaveBeenCalled();
 
                 // The class on the contact will now have switched.
-                expect(u.hasClass('to', contacts[0])).toBe(false);
+                await u.waitUntil(() => !u.hasClass('to', contacts[0]));
                 expect(u.hasClass('both', contacts[0])).toBe(true);
                 done();
 

+ 2 - 2
spec/spoilers.js

@@ -35,7 +35,7 @@
                     }).t(spoiler_hint)
                 .tree();
             _converse.connection._dataRecv(test_utils.createRequest(msg));
-            await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
+            await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
             const view = _converse.chatboxviews.get(sender_jid);
             await new Promise(resolve => view.once('messageInserted', resolve));
             await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')
@@ -70,7 +70,7 @@
                       'xmlns': 'urn:xmpp:spoiler:0',
                     }).tree();
             _converse.connection._dataRecv(test_utils.createRequest(msg));
-            await new Promise(resolve => _converse.api.listen.once('chatBoxInitialized', resolve));
+            await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
             const view = _converse.chatboxviews.get(sender_jid);
             await u.waitUntil(() => u.isVisible(view.el));
             await u.waitUntil(() => view.model.vcard.get('fullname') === 'Mercutio')

+ 1 - 2
src/converse-bookmark-views.js

@@ -308,8 +308,7 @@ converse.plugins.add('converse-bookmark-views', {
         }
 
         _converse.api.listen.on('bookmarksInitialized', initBookmarkViews);
-
-        _converse.api.listen.on('chatRoomOpened', view => view.setBookmarkState());
+        _converse.api.listen.on('chatRoomViewInitialized', view => view.setBookmarkState());
         /************************ END Event Handlers ************************/
     }
 });

+ 6 - 7
src/converse-chatview.js

@@ -81,9 +81,8 @@ converse.plugins.add('converse-chatview', {
                 this.listenTo(this.model, 'change:status', this.onStatusMessageChanged);
 
                 this.debouncedRender = debounce(this.render, 50);
-                if (this.model.vcard) {
-                    this.listenTo(this.model.vcard, 'change', this.debouncedRender);
-                }
+                this.listenTo(this.model, 'vcard:change', this.debouncedRender);
+
                 if (this.model.contact) {
                     this.listenTo(this.model.contact, 'destroy', this.debouncedRender);
                 }
@@ -264,11 +263,11 @@ converse.plugins.add('converse-chatview', {
 
                 /**
                  * Triggered once the {@link _converse.ChatBoxView} has been initialized
-                 * @event _converse#chatBoxInitialized
-                 * @type { _converse.ChatBoxView | _converse.HeadlinesBoxView }
-                 * @example _converse.api.listen.on('chatBoxInitialized', view => { ... });
+                 * @event _converse#chatBoxViewInitialized
+                 * @type { _converse.HeadlinesBoxView }
+                 * @example _converse.api.listen.on('chatBoxViewInitialized', view => { ... });
                  */
-                _converse.api.trigger('chatBoxInitialized', this);
+                _converse.api.trigger('chatBoxViewInitialized', this);
             },
 
             initDebounced () {

+ 0 - 1
src/converse-controlbox.js

@@ -196,7 +196,6 @@ converse.plugins.add('converse-controlbox', {
                  * @example _converse.api.listen.on('controlBoxInitialized', view => { ... });
                  */
                 _converse.api.trigger('controlBoxInitialized', this);
-                _converse.api.trigger('chatBoxInitialized', this);
             },
 
             render () {

+ 7 - 1
src/converse-headlines-view.js

@@ -53,7 +53,13 @@ converse.plugins.add('converse-headlines-view', {
                 this.render().insertHeading()
                 this.updateAfterMessagesFetched();
                 this.insertIntoDOM().hide();
-                _converse.api.trigger('chatBoxInitialized', this);
+                /**
+                 * Triggered once the {@link _converse.HeadlinesBoxView} has been initialized
+                 * @event _converse#headlinesBoxViewInitialized
+                 * @type { _converse.HeadlinesBoxView }
+                 * @example _converse.api.listen.on('headlinesBoxViewInitialized', view => { ... });
+                 */
+                _converse.api.trigger('headlinesBoxViewInitialized', this);
             },
 
             render () {

+ 1 - 4
src/converse-message-view.js

@@ -103,10 +103,6 @@ converse.plugins.add('converse-message-view', {
                     }
                 }, 50);
 
-                if (this.model.vcard) {
-                    this.listenTo(this.model.vcard, 'change', this.debouncedRender);
-                }
-
                 if (this.model.rosterContactAdded) {
                     this.model.rosterContactAdded.then(() => {
                         this.listenTo(this.model.contact, 'change:nickname', this.debouncedRender);
@@ -122,6 +118,7 @@ converse.plugins.add('converse-message-view', {
 
                 this.listenTo(this.model, 'change', this.onChanged);
                 this.listenTo(this.model, 'destroy', this.fadeOut);
+                this.listenTo(this.model, 'vcard:change', this.debouncedRender);
             },
 
             async render () {

+ 5 - 6
src/converse-muc-views.js

@@ -688,13 +688,12 @@ converse.plugins.add('converse-muc-views', {
                 await this.updateAfterMessagesFetched();
                 this.onConnectionStatusChanged();
                 /**
-                 * Triggered once a groupchat has been opened
-                 * @event _converse#chatRoomOpened
+                 * Triggered once a { @link _converse.ChatRoomView } has been opened
+                 * @event _converse#chatRoomViewInitialized
                  * @type { _converse.ChatRoomView }
-                 * @example _converse.api.listen.on('chatRoomOpened', view => { ... });
+                 * @example _converse.api.listen.on('chatRoomViewInitialized', view => { ... });
                  */
-                _converse.api.trigger('chatRoomOpened', this);
-                _converse.api.trigger('chatBoxInitialized', this);
+                _converse.api.trigger('chatRoomViewInitialized', this);
             },
 
             render () {
@@ -1707,7 +1706,7 @@ converse.plugins.add('converse-muc-views', {
                 }
             },
 
-            insertDayIndicator (next_msg_el) {
+            insertDayIndicator () {
                 this.removeEmptyHistoryFeedback();
                 return _converse.ChatBoxView.prototype.insertDayIndicator.apply(this, arguments);
             },

+ 5 - 5
src/converse-rosterview.js

@@ -339,14 +339,14 @@ converse.plugins.add('converse-rosterview', {
 
             async initialize () {
                 await this.model.initialized;
-                this.listenTo(this.model, "change", this.render);
-                this.listenTo(this.model, "highlight", this.highlight);
+                this.debouncedRender = debounce(this.render, 50);
+                this.listenTo(this.model, "change", this.debouncedRender);
                 this.listenTo(this.model, "destroy", this.remove);
+                this.listenTo(this.model, "highlight", this.highlight);
                 this.listenTo(this.model, "open", this.openChat);
                 this.listenTo(this.model, "remove", this.remove);
-
-                this.listenTo(this.model.presence, "change:show", this.render);
-                this.listenTo(this.model.vcard, 'change:fullname', this.render);
+                this.listenTo(this.model, 'vcard:change', this.debouncedRender);
+                this.listenTo(this.model.presence, "change:show", this.debouncedRender);
                 this.render();
             },
 

+ 13 - 3
src/headless/converse-chat.js

@@ -89,6 +89,12 @@ converse.plugins.add('converse-chat', {
                     this.on('change:put', this.uploadFile, this);
                 }
                 this.setTimerForEphemeralMessage();
+                /**
+                 * Triggered once a {@link _converse.Message} has been created and initialized.
+                 * @event _converse#messageInitialized
+                 * @type { _converse.Message}
+                 * @example _converse.api.listen.on('messageInitialized', model => { ... });
+                 */
                 await _converse.api.trigger('messageInitialized', this, {'Synchronous': true});
                 this.initialized.resolve();
             },
@@ -298,9 +304,6 @@ converse.plugins.add('converse-chat', {
                 }
                 this.set({'box_id': `box-${btoa(jid)}`});
 
-                if (_converse.vcards) {
-                    this.vcard = _converse.vcards.findWhere({'jid': jid}) || _converse.vcards.create({'jid': jid});
-                }
                 if (this.get('type') === _converse.PRIVATE_CHAT_TYPE) {
                     this.presence = _converse.presences.findWhere({'jid': jid}) || _converse.presences.create({'jid': jid});
                     await this.setRosterContact(jid);
@@ -308,6 +311,13 @@ converse.plugins.add('converse-chat', {
                 this.on('change:chat_state', this.sendChatState, this);
                 this.initMessages();
                 await this.fetchMessages();
+                /**
+                 * Triggered once a {@link _converse.ChatBox} has been created and initialized.
+                 * @event _converse#chatBoxInitialized
+                 * @type { _converse.ChatBox}
+                 * @example _converse.api.listen.on('chatBoxInitialized', model => { ... });
+                 */
+                await _converse.api.trigger('chatBoxInitialized', this, {'Synchronous': true});
                 this.initialized.resolve();
             },
 

+ 1 - 1
src/headless/converse-mam.js

@@ -235,7 +235,7 @@ converse.plugins.add('converse-mam', {
         /************************ BEGIN Event Handlers ************************/
         _converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.MAM));
         _converse.api.listen.on('serviceDiscovered', getMAMPrefsFromFeature);
-        _converse.api.listen.on('chatRoomOpened', view => {
+        _converse.api.listen.on('chatRoomViewInitialized', view => {
             if (_converse.muc_show_logs_before_join) {
                 // If we want to show MAM logs before entering the MUC, we need
                 // to be informed once it's clear that this MUC supports MAM.

+ 16 - 42
src/headless/converse-muc.js

@@ -249,8 +249,14 @@ converse.plugins.add('converse-muc', {
                 }
                 if (!this.setTimerForEphemeralMessage()) {
                     this.setOccupant();
-                    this.setVCard();
                 }
+                /**
+                 * Triggered once a {@link _converse.ChatRoomMessageInitialized} has been created and initialized.
+                 * @event _converse#chatRoomMessageInitialized
+                 * @type { _converse.ChatRoomMessages}
+                 * @example _converse.api.listen.on('chatRoomMessageInitialized', model => { ... });
+                 */
+                _converse.api.trigger('chatRoomMessageInitialized', this);
             },
 
             onOccupantRemoved () {
@@ -288,37 +294,7 @@ converse.plugins.add('converse-muc', {
                 } else {
                     this.listenTo(chatbox.occupants, 'add', this.onOccupantAdded);
                 }
-
-            },
-
-            getVCardForChatroomOccupant () {
-                const chatbox = get(this, 'collection.chatbox');
-                const nick = Strophe.getResourceFromJid(this.get('from'));
-
-                if (chatbox && chatbox.get('nick') === nick) {
-                    return _converse.xmppstatus.vcard;
-                } else {
-                    const jid = this.occupant && this.occupant.get('jid') || this.get('from');
-                    if (jid) {
-                        return _converse.vcards.findWhere({jid}) || _converse.vcards.create({jid});
-                    } else {
-                        log.error(`Could not assign VCard for message because no JID found! msgid: ${this.get('msgid')}`);
-                        return;
-                    }
-                }
-            },
-
-            async setVCard () {
-                await _converse.api.waitUntil('VCardsInitialized');
-                if (!_converse.vcards) {
-                    return; // VCards aren't supported
-                }
-                if (['error', 'info'].includes(this.get('type'))) {
-                    return;
-                } else {
-                    this.vcard = this.getVCardForChatroomOccupant();
-                }
-            },
+            }
         });
 
 
@@ -378,10 +354,9 @@ converse.plugins.add('converse-muc', {
                 }
             },
 
-            async initialize() {
+            async initialize () {
                 this.initialized = u.getResolveablePromise();
 
-                this.setVCard();
                 this.set('box_id', `box-${btoa(this.get('jid'))}`);
 
                 await this.restoreSession();
@@ -397,17 +372,16 @@ converse.plugins.add('converse-muc', {
                 if (!restored) {
                     this.join();
                 }
+                /**
+                 * Triggered once a {@link _converse.ChatRoom} has been created and initialized.
+                 * @event _converse#chatRoomInitialized
+                 * @type { _converse.ChatRoom }
+                 * @example _converse.api.listen.on('chatRoomInitialized', model => { ... });
+                 */
+                await _converse.api.trigger('chatRoomInitialized', this, {'Synchronous': true});
                 this.initialized.resolve();
             },
 
-            async setVCard () {
-                await _converse.api.waitUntil('VCardsInitialized');
-                if (_converse.vcards) {
-                    this.vcard = _converse.vcards.findWhere({'jid': this.get('jid')}) ||
-                        _converse.vcards.create({'jid': this.get('jid')});
-                }
-            },
-
             /**
              * Checks whether we're still joined and if so, restores the MUC state from cache.
              * @private

+ 71 - 33
src/headless/converse-vcard.js

@@ -9,8 +9,9 @@
 import "./converse-status";
 import converse from "./converse-core";
 import tpl_vcard from "./templates/vcard.html";
+import { get, has, isString } from "lodash";
 
-const { Backbone, Strophe, _, $iq, dayjs, } = converse.env;
+const { Backbone, Strophe, $iq, dayjs } = converse.env;
 const u = converse.env.utils;
 
 
@@ -84,7 +85,7 @@ converse.plugins.add('converse-vcard', {
                 } else {
                     (attrs = {})[key] = val;
                 }
-                if (_.has(attrs, 'image') && !attrs['image']) {
+                if (has(attrs, 'image') && !attrs['image']) {
                     attrs['image'] = _converse.DEFAULT_IMAGE;
                     attrs['image_type'] = _converse.DEFAULT_IMAGE_TYPE;
                     return Backbone.Model.prototype.set.call(this, attrs, options);
@@ -116,13 +117,13 @@ converse.plugins.add('converse-vcard', {
             if (vcard !== null) {
                 result = {
                     'stanza': iq,
-                    'fullname': _.get(vcard.querySelector('FN'), 'textContent'),
-                    'nickname': _.get(vcard.querySelector('NICKNAME'), 'textContent'),
-                    'image': _.get(vcard.querySelector('PHOTO BINVAL'), 'textContent'),
-                    'image_type': _.get(vcard.querySelector('PHOTO TYPE'), 'textContent'),
-                    'url': _.get(vcard.querySelector('URL'), 'textContent'),
-                    'role': _.get(vcard.querySelector('ROLE'), 'textContent'),
-                    'email': _.get(vcard.querySelector('EMAIL USERID'), 'textContent'),
+                    'fullname': get(vcard.querySelector('FN'), 'textContent'),
+                    'nickname': get(vcard.querySelector('NICKNAME'), 'textContent'),
+                    'image': get(vcard.querySelector('PHOTO BINVAL'), 'textContent'),
+                    'image_type': get(vcard.querySelector('PHOTO TYPE'), 'textContent'),
+                    'url': get(vcard.querySelector('URL'), 'textContent'),
+                    'role': get(vcard.querySelector('ROLE'), 'textContent'),
+                    'email': get(vcard.querySelector('EMAIL USERID'), 'textContent'),
                     'vcard_updated': (new Date()).toISOString(),
                     'vcard_error': undefined
                 };
@@ -135,6 +136,7 @@ converse.plugins.add('converse-vcard', {
             return result;
         }
 
+
         function createStanza (type, jid, vcard_el) {
             const iq = $iq(jid ? {'type': type, 'to': jid} : {'type': type});
             if (!vcard_el) {
@@ -145,6 +147,7 @@ converse.plugins.add('converse-vcard', {
             return iq;
         }
 
+
         async function getVCard (_converse, jid) {
             const to = Strophe.getBareJidFromJid(jid) === _converse.bare_jid ? null : jid;
             let iq;
@@ -160,7 +163,54 @@ converse.plugins.add('converse-vcard', {
             return onVCardData(jid, iq);
         }
 
-        /************************ BEGIN Event Handlers ************************/
+
+        async function setVCardOnModel (model) {
+            let jid;
+            if (model instanceof _converse.Message) {
+                if (model.get('type') === 'error') {
+                    return;
+                }
+                jid = model.get('from');
+            } else {
+                jid = model.get('jid');
+            }
+            await _converse.api.waitUntil('VCardsInitialized');
+            model.vcard = _converse.vcards.findWhere({'jid': jid});
+            if (!model.vcard) {
+                model.vcard = _converse.vcards.create({'jid': jid});
+            }
+            model.vcard.on('change', () => model.trigger('vcard:change'));
+        }
+
+
+        function getVCardForChatroomOccupant (message) {
+            const chatbox = get(message, 'collection.chatbox');
+            const nick = Strophe.getResourceFromJid(message.get('from'));
+
+            if (chatbox && chatbox.get('nick') === nick) {
+                return _converse.xmppstatus.vcard;
+            } else {
+                const jid = message.occupant && message.occupant.get('jid') || message.get('from');
+                if (jid) {
+                    return _converse.vcards.findWhere({jid}) || _converse.vcards.create({jid});
+                } else {
+                    log.error(`Could not assign VCard for message because no JID found! msgid: ${message.get('msgid')}`);
+                    return;
+                }
+            }
+        }
+
+
+        async function setVCardOnMUCMessage (message) {
+            await _converse.api.waitUntil('VCardsInitialized');
+            if (['error', 'info'].includes(message.get('type'))) {
+                return;
+            } else {
+                message.vcard = getVCardForChatroomOccupant(message);
+            }
+        }
+
+
         _converse.initVCardCollection = async function () {
             _converse.vcards = new _converse.VCards();
             _converse.vcards.browserStorage = _converse.createStore(`${_converse.bare_jid}-converse.vcards`);
@@ -182,9 +232,8 @@ converse.plugins.add('converse-vcard', {
             _converse.api.trigger('VCardsInitialized');
         }
 
-        _converse.api.listen.on('statusInitialized', _converse.initVCardCollection);
 
-        _converse.api.listen.on('clearSession', () => {
+        function clearVCardsSession () {
             if (_converse.shouldClearCache()) {
                 _converse.api.promises.add('VCardsInitialized');
                 if (_converse.vcards) {
@@ -192,30 +241,19 @@ converse.plugins.add('converse-vcard', {
                     delete _converse.vcards;
                 }
             }
-        });
-
+        }
 
-        _converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.VCARD));
 
+        /************************ BEGIN Event Handlers ************************/
 
-        async function setVCardOnModel (model) {
-            let jid;
-            if (model instanceof _converse.Message) {
-                if (model.get('type') === 'error') {
-                    return;
-                }
-                jid = model.get('from');
-            } else {
-                jid = model.get('jid');
-            }
-            await _converse.api.waitUntil('VCardsInitialized');
-            model.vcard = _converse.vcards.findWhere({'jid': jid});
-            if (!model.vcard) {
-                model.vcard = _converse.vcards.create({'jid': jid});
-            }
-        }
-        _converse.api.listen.on('rosterContactInitialized', m => setVCardOnModel(m));
+        _converse.api.listen.on('chatBoxInitialized', m => setVCardOnModel(m));
+        _converse.api.listen.on('chatRoomInitialized', m => setVCardOnModel(m));
+        _converse.api.listen.on('chatRoomMessageInitialized', m => setVCardOnMUCMessage(m));
+        _converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.VCARD));
+        _converse.api.listen.on('clearSession', () => clearVCardsSession());
         _converse.api.listen.on('messageInitialized', m => setVCardOnModel(m));
+        _converse.api.listen.on('rosterContactInitialized', m => setVCardOnModel(m));
+        _converse.api.listen.on('statusInitialized', _converse.initVCardCollection);
 
 
         /************************ BEGIN API ************************/
@@ -275,7 +313,7 @@ converse.plugins.add('converse-vcard', {
                  * });
                  */
                  get (model, force) {
-                    if (_.isString(model)) {
+                    if (isString(model)) {
                         return getVCard(_converse, model);
                     } else if (force ||
                             !model.get('vcard_updated') ||