From b8679063c54609088325663d4a16b95edd82257a Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 5 May 2018 20:28:41 +0200 Subject: [PATCH] Use the VCards collection for roster contacts Instead of saving the vcard data on the contact model itself --- CHANGES.md | 14 ++++-- spec/chatbox.js | 2 +- spec/roster.js | 21 +++++---- src/converse-notification.js | 6 +-- src/converse-roster.js | 27 ++++++++--- src/converse-rosterview.js | 24 ++++++---- src/converse-vcard.js | 67 ++------------------------- src/templates/pending_contact.html | 2 +- src/templates/requesting_contact.html | 3 +- src/templates/roster_item.html | 2 +- 10 files changed, 67 insertions(+), 101 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dbcd4770e..4b61a479b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,12 @@ - Support for rendering URLs sent according to XEP-0066 Out of Band Data. - Geo-URIs (e.g. from Conversations) are now replaced by links to openstreetmap (works in reverse also) +### Bugfixes + +- Spoiler messages didn't include the message author's name. +- Documentation includes utf-8 charset to make minfied versions compatible across platforms. #1017 +- #1026 Typing in MUC shows "Typing from another device" + ### API changes - `_converse.api.vcard.get` now also accepts a `Backbone.Model` instance and has an additional `force` parameter to force fetching the vcard even if it @@ -40,12 +46,10 @@ - Extracted the views from `converse-muc.js` into `converse-muc-views.js` and where appropriate moved methods from the views into the models/collections. This makes MUC possible in headless mode. +- Created a new core plugin `converse-roster.js` which contains the models for + roster-related data. Previously this code was in `converse-core.js`. +- VCards are now stored separately from chats and roster contacts. -### Bugfixes - -- Spoiler messages didn't include the message author's name. -- Documentation includes utf-8 charset to make minfied versions compatible across platforms. #1017 -- #1026 Typing in MUC shows "Typing from another device" ## 3.3.4 (2018-03-05) diff --git a/spec/chatbox.js b/spec/chatbox.js index a61d16c64..38cc47e81 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -245,7 +245,7 @@ expect(_converse.chatboxes.length).toEqual(1); chatbox = test_utils.openChatBoxFor(_converse, contact_jid); - $el = $(_converse.rosterview.el).find('a.open-chat:contains("'+chatbox.get('fullname')+'")'); + $el = $(_converse.rosterview.el).find('a.open-chat:contains("'+chatbox.getDisplayName()+'")'); jid = $el.text().replace(/ /g,'.').toLowerCase() + '@localhost'; spyOn(_converse, 'emit'); diff --git a/spec/roster.js b/spec/roster.js index 675f657b1..e7f3be03c 100644 --- a/spec/roster.js +++ b/spec/roster.js @@ -651,15 +651,18 @@ function (done, _converse) { _addContacts(_converse); - var name; - spyOn(window, 'confirm').and.returnValue(true); - for (var i=0; i _converse.roster.at(0).vcard.get('fullname')) + .then(function () { + var name; + spyOn(window, 'confirm').and.returnValue(true); + for (var i=0; i name2? 1 : 0); } else { return _converse.STATUS_WEIGHTS[status1] < _converse.STATUS_WEIGHTS[status2] ? -1 : 1; @@ -436,12 +450,11 @@ */ return new Promise((resolve, reject) => { groups = groups || []; - name = _.isEmpty(name)? jid: name; this.sendContactAddIQ(jid, name, groups, () => { const contact = this.create(_.assignIn({ 'ask': undefined, - 'fullname': name, + 'nickname': name, groups, jid, 'requesting': false, @@ -555,7 +568,7 @@ } this.create({ 'ask': ask, - 'fullname': item.getAttribute("name") || jid, + 'nickname': item.getAttribute("name"), 'groups': groups, 'jid': jid, 'subscription': subscription @@ -585,7 +598,7 @@ 'subscription': 'none', 'ask': null, 'requesting': true, - 'fullname': nickname + 'nickname': nickname }; this.create(user_data); _converse.emit('contactRequest', user_data); diff --git a/src/converse-rosterview.js b/src/converse-rosterview.js index 2dba7f150..c4a751325 100644 --- a/src/converse-rosterview.js +++ b/src/converse-rosterview.js @@ -368,9 +368,10 @@ initialize () { this.model.on("change", this.render, this); - this.model.on("remove", this.remove, this); this.model.on("destroy", this.remove, this); this.model.on("open", this.openChat, this); + this.model.on("remove", this.remove, this); + this.model.vcard.on('change:fullname', this.render, this); }, render () { @@ -412,19 +413,23 @@ * * So in both cases the user is a "pending" contact. */ + const display_name = item.getDisplayName(); this.el.classList.add('pending-xmpp-contact'); this.el.innerHTML = tpl_pending_contact( _.extend(item.toJSON(), { - 'desc_remove': __('Click to remove %1$s as a contact', item.get('fullname') || item.get('jid')), + 'display_name': display_name, + 'desc_remove': __('Click to remove %1$s as a contact', display_name), 'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts }) ); } else if (requesting === true) { + const display_name = item.getDisplayName(); this.el.classList.add('requesting-xmpp-contact'); this.el.innerHTML = tpl_requesting_contact( _.extend(item.toJSON(), { - 'desc_accept': __("Click to accept the contact request from %1$s", item.get('fullname') || item.get('jid')), - 'desc_decline': __("Click to decline the contact request from %1$s", item.get('fullname') || item.get('jid')), + 'display_name': display_name, + 'desc_accept': __("Click to accept the contact request from %1$s", display_name), + 'desc_decline': __("Click to decline the contact request from %1$s", display_name), 'allow_chat_pending_contacts': _converse.allow_chat_pending_contacts }) ); @@ -449,12 +454,14 @@ } else if (chat_status === 'dnd') { status_icon = 'fa-minus-circle'; } + const display_name = item.getDisplayName(); this.el.innerHTML = tpl_roster_item( _.extend(item.toJSON(), { + 'display_name': display_name, 'desc_status': STATUSES[chat_status], 'status_icon': status_icon, - 'desc_chat': __('Click to chat with %1$s (JID: %2$s)', item.get('fullname') || item.get('jid'), item.get('jid')), - 'desc_remove': __('Click to remove %1$s as a contact', item.get('fullname') || item.get('jid')), + 'desc_chat': __('Click to chat with %1$s (JID: %2$s)', display_name, item.get('jid')), + 'desc_remove': __('Click to remove %1$s as a contact', display_name), 'allow_contact_removal': _converse.allow_contact_removal, 'num_unread': item.get('num_unread') || 0 }) @@ -511,7 +518,7 @@ if (ev && ev.preventDefault) { ev.preventDefault(); } _converse.roster.sendContactAddIQ( this.model.get('jid'), - this.model.get('fullname'), + this.model.getFullname(), [], () => { this.model.authorize().subscribe(); } ); @@ -633,8 +640,7 @@ } } else { matches = this.model.contacts.filter((contact) => { - const value = contact.get('fullname') || contact.get('jid'); - return !_.includes(value.toLowerCase(), q.toLowerCase()); + return !_.includes(contact.getDisplayName().toLowerCase(), q.toLowerCase()); }); } return matches; diff --git a/src/converse-vcard.js b/src/converse-vcard.js index 7a18b5cc7..289661923 100644 --- a/src/converse-vcard.js +++ b/src/converse-vcard.js @@ -1,10 +1,8 @@ -// Converse.js (A browser based XMPP chat client) +// Converse.js // http://conversejs.org // -// Copyright (c) 2012-2017, Jan-Carel Brand +// Copyright (c) 2012-2018, the Converse.js developers // Licensed under the Mozilla Public License (MPLv2) -// -/*global define */ (function (root, factory) { define(["converse-core", "crypto", "strophe.vcard"], factory); @@ -36,11 +34,9 @@ } function onVCardError (_converse, jid, iq, errback) { - const contact = _converse.roster.get(jid); - if (contact) { - contact.save({'vcard_updated': moment().format() }); + if (errback) { + errback({'stanza': iq, 'jid': jid}); } - if (errback) { errback({'stanza': iq, 'jid': jid}); } } function getVCard (_converse, jid) { @@ -63,34 +59,6 @@ converse.plugins.add('converse-vcard', { - // FIXME: After refactoring, the dependency switches, from - // converse-roster to converse-vcard - dependencies: ["converse-roster"], - - overrides: { - // Overrides mentioned here will be picked up by converse.js's - // plugin architecture they will replace existing methods on the - // relevant objects or classes. - // - // New functions which don't exist yet can also be added. - - RosterContacts: { - createRequestingContact (presence) { - const { _converse } = this.__super__; - const bare_jid = Strophe.getBareJidFromJid(presence.getAttribute('from')); - - _converse.api.vcard.get(bare_jid) - .then(_.partial(_converse.createRequestingContactFromVCard, presence)) - .catch((vcard) => { - _converse.log( - `Error while retrieving vcard for ${vcard.jid}`, - Strophe.LogLevel.WARN); - _converse.createRequestingContactFromVCard(presence, vcard.stanza, vcard.jid); - }); - } - } - }, - initialize () { /* The initialize function gets called as soon as the plugin is * loaded by converse.js's plugin machinery. @@ -106,29 +74,6 @@ }); - _converse.createRequestingContactFromVCard = function (presence, vcard) { - const bare_jid = Strophe.getBareJidFromJid(presence.getAttribute('from')); - let fullname = vcard.fullname; - if (!fullname) { - const nick_el = sizzle(`nick[xmlns="${Strophe.NS.NICK}"]`, presence); - fullname = nick_el.length ? nick_el[0].textContent : bare_jid; - } - const user_data = { - 'jid': bare_jid, - 'subscription': 'none', - 'ask': null, - 'requesting': true, - 'fullname': fullname, - 'image': vcard.image, - 'image_type': vcard.image_type, - 'image_hash': vcard.image_hash, - 'url': vcard.url, - 'vcard_updated': moment().format() - }; - _converse.roster.create(user_data); - _converse.emit('contactRequest', user_data); - }; - /* Event handlers */ _converse.initVCardCollection = function () { _converse.vcards = new _converse.VCards(); @@ -142,10 +87,6 @@ _converse.connection.disco.addFeature(Strophe.NS.VCARD); }); - _converse.on('initialized', () => { - _converse.roster.on("add", (contact) => _converse.api.vcard.update(contact)); - }); - _converse.on('statusInitialized', function fetchOwnVCard () { _converse.api.disco.supports(Strophe.NS.VCARD, _converse.domain) .then((result) => { diff --git a/src/templates/pending_contact.html b/src/templates/pending_contact.html index c0055124b..f08be362e 100644 --- a/src/templates/pending_contact.html +++ b/src/templates/pending_contact.html @@ -1,7 +1,7 @@ {[ if (o.allow_chat_pending_contacts) { ]} {[ } ]} -{{{o.fullname}}} +{{{o.display_name}}} {[ if (o.allow_chat_pending_contacts) { ]} {[ } ]} diff --git a/src/templates/requesting_contact.html b/src/templates/requesting_contact.html index 4d35c4cf7..5aafb37b6 100644 --- a/src/templates/requesting_contact.html +++ b/src/templates/requesting_contact.html @@ -1,8 +1,7 @@ {[ if (o.allow_chat_pending_contacts) { ]} {[ } ]} -{{{o.fullname}}} +{{{o.display_name}}} {[ if (o.allow_chat_pending_contacts) { ]} {[ } ]} diff --git a/src/templates/roster_item.html b/src/templates/roster_item.html index 4b1273119..8e8c89cec 100644 --- a/src/templates/roster_item.html +++ b/src/templates/roster_item.html @@ -4,7 +4,7 @@ {[ if (o.num_unread) { ]} {{{ o.num_unread }}} {[ } ]} - {{{o.fullname || o.jid}}} + {{{o.display_name}}} {[ if (o.allow_contact_removal) { ]} {[ } ]}