buddy_list: Clean up selector references.

In this cleanup I make it so that all jQuery selector references
are toward the top of the module, and we do all finds relative
to the container ('#user_presences').

This will make it easier to make a better list abstraction for
the buddy list, for things like progressive rendering.
This commit is contained in:
Steve Howell 2018-04-20 14:13:39 +00:00 committed by Tim Abbott
parent 65d8eb3189
commit f11b3c9934
2 changed files with 118 additions and 57 deletions

View File

@ -295,6 +295,8 @@ function reset_jquery() {
$('#user_presences li.user_sidebar_entry.narrow-filter').last = function () { $('#user_presences li.user_sidebar_entry.narrow-filter').last = function () {
return $('li.user_sidebar_entry[data-user-id="' + user_order[user_count - 1] + '"]'); return $('li.user_sidebar_entry[data-user-id="' + user_order[user_count - 1] + '"]');
}; };
buddy_list.container = $('#user_presences');
} }
reset_jquery(); 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() { (function test_PM_update_dom_counts() {
const value = $.create('alice-value'); const value = $.create('alice-value');
const count = $.create('alice-count'); const count = $.create('alice-count');
const pm_key = alice.user_id.toString(); 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); count.set_find_results('.value', value);
li.set_find_results('.count', count); li.set_find_results('.count', count);
count.set_parent(li); 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() { (function test_insert_one_user_into_empty_list() {
const alice_li = $.create('alice list item'); 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; let appended_html;
$('#user_presences').append = function (html) { $('#user_presences').append = function (html) {
appended_html = html; appended_html = html;
buddy_list_add(alice.user_id, alice_li);
}; };
$.stub_selector('#user_presences li', { var removed;
toArray: () => [], 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); activity.insert_user_into_list(alice.user_id);
assert(appended_html.indexOf('data-user-id="1"') > 0); assert(appended_html.indexOf('data-user-id="1"') > 0);
assert(appended_html.indexOf('user_active') > 0); assert(appended_html.indexOf('user_active') > 0);
assert(removed);
}()); }());
reset_jquery();
(function test_insert_fred_after_alice() { (function test_insert_fred_after_alice() {
const alice_li = $.create('alice list item');
const fred_li = $.create('fred list item'); const fred_li = $.create('fred list item');
// These selectors are here to avoid some short-circuit logic. alice_li.attr('data-user-id', alice.user_id);
$('#user_presences').set_find_results('[data-user-id="2"]', fred_li);
let appended_html; let appended_html;
$('#user_presences').append = function (html) { $('#user_presences').append = function (html) {
appended_html = html; appended_html = html;
buddy_list_add(fred.user_id, fred_li);
}; };
$('<fake html for alice>').attr = function (attr_name) { var removed;
assert.equal(attr_name, 'data-user-id'); const remove_stub = {
return alice.user_id; remove: () => {
}; removed = true;
$.stub_selector('#user_presences li', {
toArray: function () {
return [
'<fake html for alice>',
];
}, },
}); };
buddy_list_add(fred.user_id, remove_stub);
simulate_list_items([alice_li]);
activity.insert_user_into_list(fred.user_id); activity.insert_user_into_list(fred.user_id);
assert(appended_html.indexOf('data-user-id="2"') > 0); assert(appended_html.indexOf('data-user-id="2"') > 0);
assert(appended_html.indexOf('user_active') > 0); assert(appended_html.indexOf('user_active') > 0);
assert(removed);
}()); }());
reset_jquery();
(function test_insert_fred_before_jill() { (function test_insert_fred_before_jill() {
const fred_li = $.create('fred-li'); const fred_li = $.create('fred-li');
const jill_li = $.create('jill-li');
// These selectors are here to avoid some short-circuit logic. jill_li.attr('data-user-id', jill.user_id);
$('#user_presences').set_find_results('[data-user-id="2"]', fred_li);
$('<fake-dom-for-jill').attr = function (attr_name) { var before_html;
assert.equal(attr_name, 'data-user-id'); jill_li.before = function (html) {
return jill.user_id;
};
$.stub_selector('#user_presences li', {
toArray: function () {
return [
'<fake-dom-for-jill',
];
},
});
let before_html;
$('<fake-dom-for-jill').before = function (html) {
before_html = html; before_html = html;
buddy_list_add(fred.user_id, fred_li);
}; };
var removed;
const remove_stub = {
remove: () => {
removed = true;
},
};
buddy_list_add(fred.user_id, remove_stub);
simulate_list_items([jill_li]);
activity.insert_user_into_list(fred.user_id); activity.insert_user_into_list(fred.user_id);
assert(before_html.indexOf('data-user-id="2"') > 0); assert(before_html.indexOf('data-user-id="2"') > 0);
assert(before_html.indexOf('user_active') > 0); assert(before_html.indexOf('user_active') > 0);
assert(removed);
}()); }());
// Reset jquery here. // Reset jquery here.
@ -750,6 +775,8 @@ $('.user-list-filter').parent = function () {
activity.update_huddles = function () {}; activity.update_huddles = function () {};
}()); }());
reset_jquery();
(function test_set_user_status() { (function test_set_user_status() {
const server_time = 500; const server_time = 500;
const info = { const info = {
@ -758,19 +785,25 @@ $('.user-list-filter').parent = function () {
timestamp: server_time, 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; presence.presence_info[alice.user_id] = undefined;
activity.set_user_status(me.email, info, server_time); activity.set_user_status(me.email, info, server_time);
assert(!inserted);
assert.equal(presence.presence_info[alice.user_id], undefined); assert.equal(presence.presence_info[alice.user_id], undefined);
activity.set_user_status(alice.email, info, server_time); activity.set_user_status(alice.email, info, server_time);
assert(inserted);
const expected = { status: 'active', mobile: false, last_active: 500 }; const expected = { status: 'active', mobile: false, last_active: 500 };
assert.deepEqual(presence.presence_info[alice.user_id], expected); assert.deepEqual(presence.presence_info[alice.user_id], expected);
activity.set_user_status(alice.email, info, server_time); activity.set_user_status(alice.email, info, server_time);

View File

@ -1,16 +1,24 @@
var buddy_list = (function () { var buddy_list = (function () {
var self = {}; var self = {};
self.populate = function (opts) { self.container_sel = '#user_presences';
var user_info = opts.items; 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}); 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) { self.find_li = function (opts) {
var user_id = opts.key; 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) { self.get_key_from_li = function (opts) {
@ -18,34 +26,54 @@ var buddy_list = (function () {
return user_id; 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) { self.insert_or_move = function (opts) {
var user_id = opts.key; var key = opts.key;
var info = opts.item; var item = opts.item;
var compare_function = opts.compare_function; var compare_function = opts.compare_function;
$('#user_presences').find('[data-user-id="' + user_id + '"]').remove(); self.maybe_remove_key({key: key});
var html = templates.render('user_presence_row', info); 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() { function insert() {
var i = 0; var i = 0;
for (i = 0; i < items.length; i += 1) { for (i = 0; i < list_items.length; i += 1) {
var li = $(items[i]); var li = list_items.eq(i);
var list_user_id = li.attr('data-user-id');
if (compare_function(user_id, list_user_id) < 0) { var list_key = self.get_key_from_li({li: li});
if (compare_function(key, list_key) < 0) {
li.before(html); li.before(html);
return; return;
} }
} }
$('#user_presences').append(html); self.container.append(html);
} }
insert(); 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; return self;
}()); }());