list_render: Clean up initialization.

For some widgets we now avoid duplicate redraw
events from this old pattern:

    widget = list_render.create(..., {
    }).init();
    widget.sort(...);

The above code was wasteful and possibly
flicker-y due to the fact that `init` and
`sort` both render.

Now we do this:

    widget = list_render.create(..., {
        init_sort: [...],
    });

For other widgets we just clean up the need
to call `init()` right after `create()`.

We also allow widgets to pass in `sort_fields`
during initialization (since you may want to
have `init_sort` use a custom sort before the
first render.)
This commit is contained in:
Steve Howell
2020-04-11 14:23:29 +00:00
committed by Tim Abbott
parent ef749dba31
commit 0681e4ba36
12 changed files with 84 additions and 100 deletions

View File

@@ -106,8 +106,7 @@ run_test('scrolling', () => {
};
container.html = (html) => { assert.equal(html, ''); };
const widget = list_render.create(container, items, opts);
widget.init();
list_render.create(container, items, opts);
assert.deepEqual(
container.appended_data.html(),
@@ -154,7 +153,6 @@ run_test('filtering', () => {
container.html = (html) => { assert.equal(html, ''); };
let widget = list_render.create(container, list, opts);
widget.init();
let expected_html =
'<div>apple</div>' +
@@ -186,7 +184,7 @@ run_test('filtering', () => {
];
widget.data(new_data);
widget.init();
widget.redraw();
expected_html =
'<div>greta</div>' +
'<div>gary</div>' +

View File

@@ -77,7 +77,7 @@ function render_attachments_ui() {
const uploaded_files_table = $("#uploaded_files_table").expectOne();
const $search_input = $("#upload_file_search");
const list = list_render.create(uploaded_files_table, attachments, {
list_render.create(uploaded_files_table, attachments, {
name: "uploaded-files-list",
modifier: function (attachment) {
return render_uploaded_files_list({ attachment: attachment });
@@ -92,11 +92,12 @@ function render_attachments_ui() {
},
},
parent_container: $('#attachments-settings').expectOne(),
}).init();
init_sort: ['numeric', 'create_time'],
sort_fields: {
mentioned_in: sort_mentioned_in,
},
});
list.sort('numeric', 'create_time');
list.add_sort_function("mentioned_in", sort_mentioned_in);
ui.reset_scrollbar(uploaded_files_table.closest(".progressive-table-wrapper"));
}

View File

@@ -50,15 +50,12 @@ exports.create = function ($container, list, opts) {
// this memoizes the results and will return a previously invoked
// instance
if (opts.name && DEFAULTS.instances.get(opts.name)) {
// the false flag here means "don't run `init`". This is because a
// user is likely reinitializing and will have put .init() afterwards.
// This happens when the same codepath is hit multiple times.
return DEFAULTS.instances.get(opts.name)
.set_container($container)
.set_opts(opts)
.set_up_event_handlers()
.data(list)
.init();
const old_widget = DEFAULTS.instances.get(opts.name);
old_widget.data(list);
old_widget.redraw();
return old_widget;
}
const meta = {
@@ -129,17 +126,14 @@ exports.create = function ($container, list, opts) {
$container.append($(html));
meta.offset += load_count;
return this;
};
// Fills the container with an initial batch of items.
// Needs to be enough to exceed the max height, so that a
// scrollable area is created.
widget.init = function () {
this.clear();
this.render(DEFAULTS.INITIAL_RENDER_COUNT);
return this;
widget.redraw = function () {
widget.clear();
widget.render(DEFAULTS.INITIAL_RENDER_COUNT);
};
widget.filter = function (map_function) {
@@ -169,40 +163,21 @@ exports.create = function ($container, list, opts) {
widget.clear();
return this;
return;
}
blueslip.warn("The data object provided to the progressive" +
" list render is invalid");
return this;
};
widget.clear = function () {
$container.html("");
meta.offset = 0;
return this;
};
widget.set_container = function ($new_container) {
if ($new_container) {
$container = $new_container;
}
return this;
};
widget.set_opts = function (new_opts) {
if (opts) {
opts = new_opts;
}
return this;
};
widget.reverse = function () {
meta.filtered_list.reverse();
widget.init();
return this;
widget.redraw();
};
// the sorting function is either the function or string that calls the
@@ -237,7 +212,7 @@ exports.create = function ($container, list, opts) {
if (!do_not_display) {
// clear and re-initialize the list with the newly filtered subset
// of items.
widget.init();
widget.redraw();
if (opts.filter && opts.filter.onupdate) {
opts.filter.onupdate();
@@ -245,10 +220,6 @@ exports.create = function ($container, list, opts) {
}
};
widget.add_sort_function = function (name, sorting_function) {
meta.sorting_functions.set(name, sorting_function);
};
// generic sorting functions are ones that will use a specified prop
// and perform a sort on it with the given sorting function.
widget.add_generic_sort_function = function (name, sorting_function) {
@@ -296,21 +267,19 @@ exports.create = function ($container, list, opts) {
// from the last sort.
// it will then also not run an update in the DOM (because we
// pass `true`), because it will update regardless below at
// `widget.init()`.
// `widget.redraw()`.
widget.sort(undefined, meta.prop, true);
filter_list(value);
// clear and re-initialize the list with the newly filtered subset
// of items.
widget.init();
widget.redraw();
if (opts.filter.onupdate) {
opts.filter.onupdate();
}
});
}
return this;
};
// add built-in generic sort functions.
@@ -344,6 +313,18 @@ exports.create = function ($container, list, opts) {
widget.set_up_event_handlers();
if (opts.sort_fields) {
for (const [name, sorting_function] of Object.entries(opts.sort_fields)) {
meta.sorting_functions.set(name, sorting_function);
}
}
if (opts.init_sort) {
widget.sort(...opts.init_sort);
} else {
widget.redraw();
}
// Save the instance for potential future retrieval if a name is provided.
if (opts.name) {
DEFAULTS.instances.set(opts.name, widget);

View File

@@ -67,7 +67,7 @@ exports.populate_emoji = function (emoji_data) {
}
const emoji_table = $('#admin_emoji_table').expectOne();
const emoji_list = list_render.create(emoji_table, Object.values(emoji_data), {
list_render.create(emoji_table, Object.values(emoji_data), {
name: "emoji_list",
modifier: function (item) {
if (item.deactivated !== true) {
@@ -93,10 +93,11 @@ exports.populate_emoji = function (emoji_data) {
},
},
parent_container: $("#emoji-settings").expectOne(),
}).init();
emoji_list.sort("alphabetic", "name");
emoji_list.add_sort_function("author_full_name", sort_author_full_name);
sort_fields: {
author_full_name: sort_author_full_name,
},
init_sort: ['alphabetic', 'name'],
});
loading.destroy_indicator($('#admin_page_emoji_loading_indicator'));
};

View File

@@ -37,7 +37,7 @@ exports.populate_exports_table = function (exports) {
}
const exports_table = $('#admin_exports_table').expectOne();
const exports_list = list_render.create(exports_table, Object.values(exports), {
list_render.create(exports_table, Object.values(exports), {
name: "admin_exports_list",
modifier: function (data) {
if (data.deleted_timestamp === null) {
@@ -65,11 +65,11 @@ exports.populate_exports_table = function (exports) {
},
},
parent_container: $("#data-exports").expectOne(),
}).init();
exports_list.add_sort_function("user", sort_user);
exports_list.sort("user");
init_sort: [sort_user],
sort_fields: {
user: sort_user,
},
});
};
exports.set_up = function () {

View File

@@ -46,7 +46,7 @@ function populate_invites(invites_data) {
const invites_table = $("#admin_invites_table").expectOne();
const invites_list = list_render.create(invites_table, invites_data.invites, {
list_render.create(invites_table, invites_data.invites, {
name: 'admin_invites_list',
modifier: function (item) {
item.invited_absolute_time = timerender.absolute_time(item.invited * 1000);
@@ -64,11 +64,12 @@ function populate_invites(invites_data) {
},
},
parent_container: $("#admin-invites-list").expectOne(),
init_sort: [sort_invitee],
sort_fields: {
invitee: sort_invitee,
},
});
invites_list.sort('invitee');
invites_list.add_sort_function('invitee', sort_invitee);
loading.destroy_indicator($('#admin_page_invites_loading_indicator'));
}

View File

@@ -60,10 +60,12 @@ exports.populate_filters = function (filters_data) {
},
},
parent_container: $("#filter-settings").expectOne(),
}).init();
filters_list.add_sort_function("pattern", sort_pattern);
filters_list.add_sort_function("url", sort_url);
init_sort: [sort_pattern],
sort_fields: {
pattern: sort_pattern,
url: sort_url,
},
});
const active_col = $('.admin_filters_table th.active').expectOne();
filters_list.sort(

View File

@@ -57,7 +57,7 @@ function rerender_ui() {
is_disabled: settings_config.all_notifications().show_push_notifications_tooltip,
});
},
}).init();
});
if (unmatched_streams.length === 0) {
unmatched_streams_table.css("display", "none");

View File

@@ -34,7 +34,7 @@ exports.default_code_language_widget = (function (element_id) {
return item.name.toLowerCase().includes(value);
},
},
}).init();
});
$(`#${element_id} .dropdown-search`).click(function (e) {
e.stopPropagation();
});
@@ -451,7 +451,7 @@ exports.populate_notifications_stream_dropdown = function (stream_list) {
ui.reset_scrollbar(dropdown_list_body);
},
},
}).init();
});
$("#id_realm_notifications_stream .dropdown-search").click(function (e) {
e.stopPropagation();
@@ -477,7 +477,7 @@ exports.populate_signup_notifications_stream_dropdown = function (stream_list) {
return item.name.toLowerCase().includes(value);
},
},
}).init();
});
$("#id_realm_signup_notifications_stream .dropdown-search").click(function (e) {
e.stopPropagation();

View File

@@ -23,7 +23,7 @@ exports.build_default_stream_table = function () {
const stream_ids = stream_data.get_default_stream_ids();
const subs = stream_ids.map(stream_data.get_sub_by_id);
const streams_list = list_render.create(table, subs, {
list_render.create(table, subs, {
name: "default_streams_list",
modifier: function (item) {
const row = $(render_admin_default_streams_list({
@@ -42,9 +42,8 @@ exports.build_default_stream_table = function () {
},
},
parent_container: $("#admin-default-streams-list").expectOne(),
}).init();
streams_list.sort("alphabetic", "name");
init_sort: ['alphabetic', 'name'],
});
loading.destroy_indicator($('#admin_page_default_streams_loading_indicator'));
};

View File

@@ -184,7 +184,7 @@ function populate_users(realm_people_data) {
};
const $bots_table = $("#admin_bots_table");
const bot_list = list_render.create($bots_table, bots, {
list_render.create($bots_table, bots, {
name: "admin_bot_list",
modifier: function (item) {
return render_admin_user_list({
@@ -203,11 +203,11 @@ function populate_users(realm_people_data) {
onupdate: reset_scrollbar($bots_table),
},
parent_container: $("#admin-bot-list").expectOne(),
}).init();
bot_list.sort("alphabetic", "full_name");
bot_list.add_sort_function("bot_owner", sort_bot_owner);
init_sort: ['alphabetic', 'full_name'],
sort_fields: {
bot_owner: sort_bot_owner,
},
});
function get_rendered_last_activity(item) {
const today = new XDate();
@@ -222,7 +222,7 @@ function populate_users(realm_people_data) {
}
const $users_table = $("#admin_users_table");
const users_list = list_render.create($users_table, active_users, {
list_render.create($users_table, active_users, {
name: "users_table_list",
modifier: function (item) {
const $row = $(render_admin_user_list({
@@ -240,15 +240,15 @@ function populate_users(realm_people_data) {
onupdate: reset_scrollbar($users_table),
},
parent_container: $("#admin-user-list").expectOne(),
}).init();
users_list.sort("alphabetic", "full_name");
users_list.add_sort_function("role", sort_role);
users_list.add_sort_function("last_active", sort_last_active);
init_sort: ['alphabetic', 'full_name'],
sort_fields: {
role: sort_role,
last_active: sort_last_active,
},
});
const $deactivated_users_table = $("#admin_deactivated_users_table");
const deactivated_users_list = list_render.create($deactivated_users_table, deactivated_users, {
list_render.create($deactivated_users_table, deactivated_users, {
name: "deactivated_users_table_list",
modifier: function (item) {
return render_admin_user_list({
@@ -263,10 +263,11 @@ function populate_users(realm_people_data) {
onupdate: reset_scrollbar($deactivated_users_table),
},
parent_container: $("#admin-deactivated-users-list").expectOne(),
}).init();
deactivated_users_list.sort("alphabetic", "full_name");
deactivated_users_list.add_sort_function("role", sort_role);
init_sort: ['alphabetic', 'full_name'],
sort_fields: {
role: sort_role,
},
});
loading.destroy_indicator($('#admin_page_users_loading_indicator'));
loading.destroy_indicator($('#admin_page_bots_loading_indicator'));

View File

@@ -217,7 +217,7 @@ function show_subscription_settings(sub_row) {
}
},
},
}).init();
});
sub_settings.find('input[name="principal"]').typeahead({
source: () => stream_data.potential_subscribers(sub),