diff --git a/frontend_tests/node_tests/activity.js b/frontend_tests/node_tests/activity.js index 0d746cc85a..725982c94f 100644 --- a/frontend_tests/node_tests/activity.js +++ b/frontend_tests/node_tests/activity.js @@ -295,6 +295,8 @@ function reset_jquery() { $('#user_presences li.user_sidebar_entry.narrow-filter').last = function () { return $('li.user_sidebar_entry[data-user-id="' + user_order[user_count - 1] + '"]'); }; + + buddy_list.container = $('#user_presences'); } reset_jquery(); @@ -353,11 +355,25 @@ reset_jquery(); ]); }()); +function simulate_list_items(items) { + const list = { + length: items.length, + eq: (i) => items[i], + }; + $('#user_presences').set_find_results('li.user_sidebar_entry', list); +} + +function buddy_list_add(user_id, stub) { + const sel = `li.user_sidebar_entry[data-user-id='${user_id}']`; + $('#user_presences').set_find_results(sel, stub); +} + (function test_PM_update_dom_counts() { const value = $.create('alice-value'); const count = $.create('alice-count'); const pm_key = alice.user_id.toString(); - const li = $("li.user_sidebar_entry[data-user-id='" + pm_key + "']"); + const li = $.create('alice stub'); + buddy_list_add(pm_key, li); count.set_find_results('.value', value); li.set_find_results('.count', count); count.set_parent(li); @@ -566,78 +582,87 @@ presence.presence_info[zoe.user_id] = { status: activity.ACTIVE }; (function test_insert_one_user_into_empty_list() { const alice_li = $.create('alice list item'); - // These selectors are here to avoid some short-circuit logic. - $('#user_presences').set_find_results('[data-user-id="1"]', alice_li); - let appended_html; $('#user_presences').append = function (html) { appended_html = html; + buddy_list_add(alice.user_id, alice_li); }; - $.stub_selector('#user_presences li', { - toArray: () => [], - }); + var removed; + const remove_stub = { + remove: () => { + removed = true; + }, + }; + buddy_list_add(alice.user_id, remove_stub); + + simulate_list_items([]); activity.insert_user_into_list(alice.user_id); assert(appended_html.indexOf('data-user-id="1"') > 0); assert(appended_html.indexOf('user_active') > 0); + assert(removed); }()); +reset_jquery(); + (function test_insert_fred_after_alice() { + const alice_li = $.create('alice list item'); const fred_li = $.create('fred list item'); - // These selectors are here to avoid some short-circuit logic. - $('#user_presences').set_find_results('[data-user-id="2"]', fred_li); + alice_li.attr('data-user-id', alice.user_id); let appended_html; $('#user_presences').append = function (html) { appended_html = html; + buddy_list_add(fred.user_id, fred_li); }; - $('').attr = function (attr_name) { - assert.equal(attr_name, 'data-user-id'); - return alice.user_id; - }; - - $.stub_selector('#user_presences li', { - toArray: function () { - return [ - '', - ]; + var removed; + const remove_stub = { + remove: () => { + removed = true; }, - }); + }; + buddy_list_add(fred.user_id, remove_stub); + + simulate_list_items([alice_li]); + activity.insert_user_into_list(fred.user_id); assert(appended_html.indexOf('data-user-id="2"') > 0); assert(appended_html.indexOf('user_active') > 0); + assert(removed); }()); +reset_jquery(); + (function test_insert_fred_before_jill() { const fred_li = $.create('fred-li'); + const jill_li = $.create('jill-li'); - // These selectors are here to avoid some short-circuit logic. - $('#user_presences').set_find_results('[data-user-id="2"]', fred_li); + jill_li.attr('data-user-id', jill.user_id); - $(' { + removed = true; + }, + }; + buddy_list_add(fred.user_id, remove_stub); + + simulate_list_items([jill_li]); + activity.insert_user_into_list(fred.user_id); assert(before_html.indexOf('data-user-id="2"') > 0); assert(before_html.indexOf('user_active') > 0); + assert(removed); }()); // Reset jquery here. @@ -750,6 +775,8 @@ $('.user-list-filter').parent = function () { activity.update_huddles = function () {}; }()); +reset_jquery(); + (function test_set_user_status() { const server_time = 500; const info = { @@ -758,19 +785,25 @@ $('.user-list-filter').parent = function () { timestamp: server_time, }, }; - const alice_li = $.create('alice-li'); - $('#user_presences').set_find_results('[data-user-id="1"]', alice_li); + buddy_data.matches_filter = () => true; - $('#user_presences').append = function () {}; + const alice_li = $.create('alice stub'); + buddy_list_add(alice.user_id, alice_li); + + var inserted; + buddy_list.insert_or_move = () => { + inserted = true; + }; - $.stub_selector('#user_presences li', { - toArray: () => [], - }); presence.presence_info[alice.user_id] = undefined; activity.set_user_status(me.email, info, server_time); + assert(!inserted); + assert.equal(presence.presence_info[alice.user_id], undefined); activity.set_user_status(alice.email, info, server_time); + assert(inserted); + const expected = { status: 'active', mobile: false, last_active: 500 }; assert.deepEqual(presence.presence_info[alice.user_id], expected); activity.set_user_status(alice.email, info, server_time); diff --git a/static/js/buddy_list.js b/static/js/buddy_list.js index 404b3e4a1f..9f8ec49d47 100644 --- a/static/js/buddy_list.js +++ b/static/js/buddy_list.js @@ -1,16 +1,24 @@ var buddy_list = (function () { var self = {}; - self.populate = function (opts) { - var user_info = opts.items; + self.container_sel = '#user_presences'; + self.item_sel = 'li.user_sidebar_entry'; + self.items_to_html = function (opts) { + var user_info = opts.items; var html = templates.render('user_presence_rows', {users: user_info}); - $('#user_presences').html(html); + return html; + }; + + self.item_to_html = function (opts) { + var html = templates.render('user_presence_row', opts.item); + return html; }; self.find_li = function (opts) { var user_id = opts.key; - return $("li.user_sidebar_entry[data-user-id='" + user_id + "']"); + var sel = self.item_sel + "[data-user-id='" + user_id + "']"; + return self.container.find(sel); }; self.get_key_from_li = function (opts) { @@ -18,34 +26,54 @@ var buddy_list = (function () { return user_id; }; + // Try to keep code below this line generic, so that we can + // extract a widget. + + self.populate = function (opts) { + var html = self.items_to_html({items: opts.items}); + self.container = $(self.container_sel); + self.container.html(html); + }; + + self.maybe_remove_key = function (opts) { + var li = self.find_li({key: opts.key}); + li.remove(); + }; + self.insert_or_move = function (opts) { - var user_id = opts.key; - var info = opts.item; + var key = opts.key; + var item = opts.item; var compare_function = opts.compare_function; - $('#user_presences').find('[data-user-id="' + user_id + '"]').remove(); - var html = templates.render('user_presence_row', info); + self.maybe_remove_key({key: key}); + var html = self.item_to_html({item: item}); - var items = $('#user_presences li').toArray(); + var list_items = self.container.find(self.item_sel); function insert() { var i = 0; - for (i = 0; i < items.length; i += 1) { - var li = $(items[i]); - var list_user_id = li.attr('data-user-id'); - if (compare_function(user_id, list_user_id) < 0) { + for (i = 0; i < list_items.length; i += 1) { + var li = list_items.eq(i); + + var list_key = self.get_key_from_li({li: li}); + + if (compare_function(key, list_key) < 0) { li.before(html); return; } } - $('#user_presences').append(html); + self.container.append(html); } insert(); }; + // This is a bit of a hack to make sure we at least have + // an empty list to start, before we get the initial payload. + self.container = $(self.container_sel); + return self; }());