Update to latest backbone.overview which debounces sorting on `add` event

This commit is contained in:
JC Brand 2019-06-27 11:27:05 +02:00
parent 11da69b0d7
commit 98215deb21
9 changed files with 95 additions and 32 deletions

View File

@ -24,7 +24,7 @@
"ignoreMethods": [
"assign", "every", "keys", "find", "endsWith", "startsWith", "filter",
"reduce", "isArray", "create", "map", "replace", "some", "toLower",
"split", "trim", "forEach", "toUpperCase", "includes", "values"
"split", "trim", "forEach", "toUpperCase", "includes", "values", "padStart"
]
}],
"lodash/import-scope": "off",

4
package-lock.json generated
View File

@ -2673,8 +2673,8 @@
"dev": true
},
"backbone.overview": {
"version": "github:jcbrand/Backbone.Overview#b3e759127d859c90e8e21700a9a5714a3b828f0a",
"from": "github:jcbrand/Backbone.Overview#b3e759127d859c90e8e21700a9a5714a3b828f0a",
"version": "github:jcbrand/Backbone.Overview#d83d0fc0e40aaf3fb5b4db81576b0eba46d6739a",
"from": "github:jcbrand/Backbone.Overview#d83d0fc0e40aaf3fb5b4db81576b0eba46d6739a",
"dev": true,
"requires": {
"lodash": "^4.17.11"

View File

@ -57,7 +57,7 @@
"@fortawesome/fontawesome-free": "5.3.1",
"babel-loader": "^8.0.4",
"backbone.nativeview": "conversejs/Backbone.NativeView#5997c8197ca594e6b8469447f28310c78bd1d95e",
"backbone.overview": "jcbrand/Backbone.Overview#b3e759127d859c90e8e21700a9a5714a3b828f0a",
"backbone.overview": "jcbrand/Backbone.Overview#d83d0fc0e40aaf3fb5b4db81576b0eba46d6739a",
"backbone.vdomview": "^1.0.1",
"bootstrap": "^4.0.0",
"bootstrap.native": "^2.0.26",

View File

@ -661,12 +661,14 @@
{ hide_open_bookmarks: true },
async function (done, _converse) {
test_utils.openControlBox();
const jid = 'room@conference.example.org';
await test_utils.waitUntilDiscoConfirmed(
_converse, _converse.bare_jid,
[{'category': 'pubsub', 'type': 'pep'}],
['http://jabber.org/protocol/pubsub#publish-options']
);
await test_utils.waitUntil(() => _converse.bookmarks);
// XXX Create bookmarks view here, otherwise we need to mock stanza
// traffic for it to get created.
_converse.bookmarksview = new _converse.BookmarksView(
@ -682,13 +684,16 @@
'nick': ' Othello'
});
expect(_converse.bookmarks.length).toBe(1);
const room_els = _converse.bookmarksview.el.querySelectorAll(".open-room");
const bmarks_view = _converse.bookmarksview;
await test_utils.waitUntil(() => bmarks_view.el.querySelectorAll(".open-room").length, 500);
const room_els = bmarks_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
// Check that it disappears once the room is opened
const bookmark = _converse.bookmarksview.el.querySelector(".open-room");
bookmark.click();
await test_utils.waitUntil(() => _converse.chatboxviews.get(jid));
expect(u.hasClass('hidden', _converse.bookmarksview.el.querySelector(".available-chatroom"))).toBeTruthy();
// Check that it reappears once the room is closed
const view = _converse.chatboxviews.get(jid);

View File

@ -1467,7 +1467,7 @@
_converse.chatboxes.onMessage(msgFactory());
await test_utils.waitUntil(() => chatbox.messages.length > 1);
expect(select_msgs_indicator().textContent).toBe('2');
view.maximize();
view.model.maximize();
expect(select_msgs_indicator()).toBeUndefined();
done();
}));

View File

@ -1484,8 +1484,8 @@
var name;
const view = _converse.chatboxviews.get('lounge@montague.lit');
const occupants = view.el.querySelector('.occupant-list');
var presence, role, jid, model;
for (var i=0; i<mock.chatroom_names.length; i++) {
var presence, role, jid;
for (let i=0; i<mock.chatroom_names.length; i++) {
name = mock.chatroom_names[i];
role = mock.chatroom_roles[name].role;
// See example 21 https://xmpp.org/extensions/xep-0045.html#enter-pres
@ -1500,15 +1500,20 @@
role: role
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(occupants.querySelectorAll('li').length).toBe(2+i);
model = view.model.occupants.where({'nick': name})[0];
const index = view.model.occupants.indexOf(model);
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(mock.chatroom_names[i]);
}
await test_utils.waitUntil(() => occupants.querySelectorAll('li').length > 2, 500);
expect(occupants.querySelectorAll('li').length).toBe(1+mock.chatroom_names.length);
mock.chatroom_names.forEach(name => {
const model = view.model.occupants.findWhere({'nick': name});
const index = view.model.occupants.indexOf(model);
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(name);
});
// Test users leaving the groupchat
// https://xmpp.org/extensions/xep-0045.html#exit
for (i=mock.chatroom_names.length-1; i>-1; i--) {
for (let i=mock.chatroom_names.length-1; i>-1; i--) {
name = mock.chatroom_names[i];
role = mock.chatroom_roles[name].role;
// See example 21 https://xmpp.org/extensions/xep-0045.html#enter-pres
@ -1554,12 +1559,17 @@
}).up()
.c('status').attrs({code:'110'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(occupants.querySelectorAll('li').length).toBe(2+i);
model = view.model.occupants.where({'nick': name})[0];
const index = view.model.occupants.indexOf(model);
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(mock.chatroom_names[i]);
}
await test_utils.waitUntil(() => occupants.querySelectorAll('li').length > 1, 500);
expect(occupants.querySelectorAll('li').length).toBe(1+mock.chatroom_names.length);
mock.chatroom_names.forEach(name => {
const model = view.model.occupants.findWhere({'nick': name});
const index = view.model.occupants.indexOf(model);
expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(name);
});
// Test users leaving the groupchat
// https://xmpp.org/extensions/xep-0045.html#exit
for (i=mock.chatroom_names.length-1; i>-1; i--) {
@ -1607,6 +1617,7 @@
_converse.connection._dataRecv(test_utils.createRequest(presence));
const view = _converse.chatboxviews.get('lounge@montague.lit');
await test_utils.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
const occupants = view.el.querySelector('.occupant-list').querySelectorAll('li .occupant-nick');
expect(occupants.length).toBe(2);
expect(occupants[0].textContent.trim()).toBe("&lt;img src=&quot;x&quot; onerror=&quot;alert(123)&quot;/&gt;");
@ -1622,7 +1633,8 @@
const view = _converse.chatboxviews.get('lounge@montague.lit');
let contact_jid = mock.cur_names[2].replace(/ /g,'.').toLowerCase() + '@montague.lit';
let occupants = view.el.querySelector('.occupant-list').querySelectorAll('li');
await test_utils.waitUntil(() => view.el.querySelectorAll('.occupant-list li').length, 500);
let occupants = view.el.querySelectorAll('.occupant-list li');
expect(occupants.length).toBe(1);
expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("romeo");
expect(occupants[0].querySelectorAll('.badge').length).toBe(2);
@ -1641,6 +1653,7 @@
.c('status').attrs({code:'110'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
await test_utils.waitUntil(() => view.el.querySelectorAll('.occupant-list li').length > 1, 500);
occupants = view.el.querySelectorAll('.occupant-list li');
expect(occupants.length).toBe(2);
expect(occupants[0].querySelector('.occupant-nick').textContent.trim()).toBe("moderatorman");
@ -1665,6 +1678,7 @@
.c('status').attrs({code:'110'}).nodeTree;
_converse.connection._dataRecv(test_utils.createRequest(presence));
await test_utils.waitUntil(() => view.el.querySelectorAll('.occupant-list li').length > 2, 500);
occupants = view.el.querySelector('.occupant-list').querySelectorAll('li');
expect(occupants.length).toBe(3);
expect(occupants[2].querySelector('.occupant-nick').textContent.trim()).toBe("visitorwoman");
@ -2209,6 +2223,7 @@
expect(view.model.get('connection_status')).toBe(converse.ROOMSTATUS.ENTERED);
const chat_content = view.el.querySelector('.chat-content');
await test_utils.waitUntil(() => view.el.querySelectorAll('li .occupant-nick').length, 500);
let occupants = view.el.querySelector('.occupant-list');
expect(occupants.childNodes.length).toBe(1);
expect(occupants.firstElementChild.querySelector('.occupant-nick').textContent.trim()).toBe("oldnick");
@ -2840,7 +2855,6 @@
async function (done, _converse) {
let iq_stanza;
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'muc.montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@muc.montague.lit');
/* We don't show join/leave messages for existing occupants. We
@ -2973,7 +2987,7 @@
"id": iq_stanza.getAttribute("id")
}).c("query", {"xmlns": "http://jabber.org/protocol/muc#admin"})
_converse.connection._dataRecv(test_utils.createRequest(result));
await test_utils.waitUntil(() => view.el.querySelectorAll('.occupant').length, 500);
await test_utils.waitUntil(() => view.el.querySelectorAll('.badge').length > 1);
expect(view.model.occupants.length).toBe(2);
expect(view.el.querySelectorAll('.occupant').length).toBe(2);

View File

@ -3,9 +3,40 @@
} (this, function (jasmine, mock, test_utils) {
var _ = converse.env._;
var $iq = converse.env.$iq;
var $pres = converse.env.$pres;
var u = converse.env.utils;
describe("Profiling", function() {
it("shows users currently present in the groupchat",
mock.initConverse(
null, ['rosterGroupsFetched'], {'muc_show_join_leave': false},
async function (done, _converse) {
test_utils.openControlBox();
await test_utils.openAndEnterChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit'),
occupants = view.el.querySelector('.occupant-list');
_.rangeRight(3000, 0).forEach(i => {
const name = `User ${i.toString().padStart(5, '0')}`;
const presence = $pres({
'to': 'romeo@montague.lit/orchard',
'from': 'lounge@montague.lit/'+name
}).c('x').attrs({xmlns:'http://jabber.org/protocol/muc#user'})
.c('item').attrs({
affiliation: 'none',
jid: name.replace(/ /g,'.').toLowerCase() + '@montague.lit',
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
// expect(occupants.querySelectorAll('li').length).toBe(1+i);
// const model = view.model.occupants.where({'nick': name})[0];
// const index = view.model.occupants.indexOf(model);
// expect(occupants.querySelectorAll('li .occupant-nick')[index].textContent.trim()).toBe(name);
});
done();
}));
xit("adds hundreds of contacts to the roster",
mock.initConverse(
null, ['rosterGroupsFetched'], {},
@ -54,7 +85,7 @@
mock.initConverse(
null, ['rosterGroupsFetched'], {},
function (done, _converse) {
// _converse.show_only_online_users = true;
_converse.roster_groups = true;
test_utils.openControlBox();

View File

@ -20,10 +20,15 @@
await test_utils.openChatRoom(_converse, 'room', 'conference.shakespeare.lit', 'JC');
expect(_.isUndefined(_converse.rooms_list_view)).toBeFalsy();
let room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
const lview = _converse.rooms_list_view
await test_utils.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
let room_els = lview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
expect(room_els[0].innerText).toBe('room@conference.shakespeare.lit');
await test_utils.openChatRoom(_converse, 'lounge', 'montague.lit', 'romeo');
await test_utils.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
@ -119,19 +124,23 @@
allow_bookmarks: false // Makes testing easier, otherwise we have to mock stanza traffic.
}, async function (done, _converse) {
let room_els, item;
let item;
await _converse.api.rooms.open('coven@chat.shakespeare.lit', {'nick': 'some1'});
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom");
const lview = _converse.rooms_list_view
await test_utils.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
let room_els = lview.el.querySelectorAll(".available-chatroom");
expect(room_els.length).toBe(1);
item = room_els[0];
expect(u.hasClass('open', item)).toBe(true);
expect(item.textContent.trim()).toBe('coven@chat.shakespeare.lit');
await _converse.api.rooms.open('balcony@chat.shakespeare.lit', {'nick': 'some1'});
room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
await test_utils.waitUntil(() => lview.el.querySelectorAll(".open-room").length > 1);
room_els = lview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(2);
room_els = _converse.rooms_list_view.el.querySelectorAll(".available-chatroom.open");
room_els = lview.el.querySelectorAll(".available-chatroom.open");
expect(room_els.length).toBe(1);
item = room_els[0];
expect(item.textContent.trim()).toBe('balcony@chat.shakespeare.lit');
@ -258,9 +267,11 @@
expect(_converse.chatboxes.length).toBe(1);
await test_utils.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
expect(_converse.chatboxes.length).toBe(2);
var room_els = _converse.rooms_list_view.el.querySelectorAll(".open-room");
const lview = _converse.rooms_list_view
await test_utils.waitUntil(() => lview.el.querySelectorAll(".open-room").length);
let room_els = lview.el.querySelectorAll(".open-room");
expect(room_els.length).toBe(1);
var close_el = _converse.rooms_list_view.el.querySelector(".close-room");
const close_el = _converse.rooms_list_view.el.querySelector(".close-room");
close_el.click();
expect(window.confirm).toHaveBeenCalledWith(
'Are you sure you want to leave the groupchat lounge@conference.shakespeare.lit?');

View File

@ -540,6 +540,7 @@ converse.plugins.add('converse-rosterview', {
"click a.group-toggle": "toggle"
},
sortImmediatelyOnAdd: true,
ItemView: _converse.RosterContactView,
listItems: 'model.contacts',
listSelector: '.roster-group-contacts',
@ -558,7 +559,7 @@ converse.plugins.add('converse-rosterview', {
// assigned to their various groups.
_converse.rosterview.on(
'rosterContactsFetchedAndProcessed',
this.sortAndPositionAllItems.bind(this)
() => this.sortAndPositionAllItems()
);
},
@ -597,7 +598,7 @@ converse.plugins.add('converse-rosterview', {
*/
let shown = 0;
const all_contact_views = this.getAll();
_.each(this.model.contacts.models, (contact) => {
this.model.contacts.forEach(contact => {
const contact_view = this.get(contact.get('id'));
if (_.includes(contacts, contact)) {
u.hideElement(contact_view.el);
@ -730,6 +731,7 @@ converse.plugins.add('converse-rosterview', {
listSelector: '.roster-contacts',
sortEvent: null, // Groups are immutable, so they don't get re-sorted
subviewIndex: 'name',
sortImmediatelyOnAdd: true,
events: {
'click a.controlbox-heading__btn.add-contact': 'showAddContactModal',
@ -758,7 +760,7 @@ converse.plugins.add('converse-rosterview', {
_converse.api.listen.on('rosterGroupsFetched', this.sortAndPositionAllItems.bind(this));
_converse.api.listen.on('rosterContactsFetched', () => {
_converse.roster.each((contact) => this.addRosterContact(contact, {'silent': true}));
_converse.roster.each(contact => this.addRosterContact(contact, {'silent': true}));
this.update();
this.updateFilter();
this.trigger('rosterContactsFetchedAndProcessed');