diff --git a/static/js/list_widget.js b/static/js/list_widget.js index cd9254fffa..1687ff2d6f 100644 --- a/static/js/list_widget.js +++ b/static/js/list_widget.js @@ -172,9 +172,7 @@ export function create($container, list, opts) { return undefined; } - const widget = { - meta, - }; + const widget = {}; widget.get_current_list = function () { return meta.filtered_list; @@ -354,6 +352,57 @@ export function create($container, list, opts) { } }; + widget.increase_rendered_offset = function () { + meta.offset = Math.min(meta.offset + 1, meta.filtered_list.length); + }; + + widget.reduce_rendered_offset = function () { + meta.offset = Math.max(meta.offset - 1, 0); + }; + + widget.remove_rendered_row = function (rendered_row) { + rendered_row.remove(); + // We removed a rendered row, so we need to reduce one offset. + widget.reduce_rendered_offset(); + }; + + widget.insert_rendered_row = function (item) { + // NOTE: Caller should call `filter_and_sort` before calling this function + // so that `meta.filtered_list` already has the `item`. + if (meta.filtered_list.length <= 2) { + // Avoids edge cases for us and could be faster too. + widget.clean_redraw(); + return; + } + if (!opts.filter.predicate(item)) { + return; + } + // We need to insert the row for it to be displayed at the + // correct position. filtered_list must contain the new item + // since we know it is not hidden from the above check. + const topic_insert_index = meta.filtered_list.findIndex( + (list_item) => list_item.last_msg_id === item.last_msg_id, + ); + // Rows greater than `offset` are not rendered in the DOM by list_widget; + // for those, there's nothing to update. + if (topic_insert_index <= meta.offset) { + if (!opts.modifier || !opts.html_selector) { + blueslip.error( + "Please specify modifier and html_selector when creating the widget.", + ); + } + const rendered_row = opts.modifier(item); + if (topic_insert_index === meta.filtered_list.length - 1) { + const $target_row = opts.html_selector(meta.filtered_list[topic_insert_index - 1]); + $target_row.after(rendered_row); + } else { + const $target_row = opts.html_selector(meta.filtered_list[topic_insert_index + 1]); + $target_row.before(rendered_row); + } + widget.increase_rendered_offset(); + } + }; + widget.sort = function (sorting_function, prop) { widget.set_sorting_function(sorting_function, prop); widget.hard_redraw(); diff --git a/static/js/recent_topics_ui.js b/static/js/recent_topics_ui.js index 436d5f7e80..4c3eb35d4d 100644 --- a/static/js/recent_topics_ui.js +++ b/static/js/recent_topics_ui.js @@ -523,10 +523,7 @@ export function inplace_rerender(topic_key) { if (row_is_focused && row_focus >= current_topics_list.length) { row_focus = current_topics_list.length - 1; } - topic_row.remove(); - // We removed a rendered row, so we need to reduce one offset. - // TODO: This is correct, but a list_widget abstractions violation. - topics_widget.meta.offset -= 1; + topics_widget.remove_rendered_row(topic_row); } else if (!is_topic_rendered && filters_should_hide_topic(topic_data)) { // In case `topic_row` is not present, our job is already done here // since it has not been rendered yet and we already removed it from @@ -537,27 +534,7 @@ export function inplace_rerender(topic_key) { topics_widget.render_item(topic_data); } else { // Final case: !is_topic_rendered && !filters_should_hide_topic(topic_data). - if (current_topics_list.length <= 2) { - // Avoids edge cases for us and could be faster too. - topics_widget.clean_redraw(); - revive_current_focus(); - return true; - } - // We need to insert the row for it to be displayed at the - // correct position. current_topics_list must contain the - // topic_item, since we know !filters_should_hide_topic(topic_data). - const topic_insert_index = current_topics_list.findIndex( - (topic_item) => topic_item.last_msg_id === topic_data.last_msg_id, - ); - // Rows greater than `offset` are not rendered in the DOM by list_widget; - // for those, there's nothing to update. - // TODO: This is correct, but a list_widget abstractions violation. - if (topic_insert_index <= topics_widget.meta.offset) { - const rendered_row = render_recent_topic_row(format_conversation(topic_data)); - const $target_row = $(`#recent_topics_table table tbody tr:eq(${topic_insert_index})`); - $target_row.before(rendered_row); - topics_widget.meta.offset += 1; - } + topics_widget.insert_rendered_row(topic_data); } setTimeout(revive_current_focus, 0); return true; diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 66a1c6ebb4..cadcb1ccf0 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -97,6 +97,7 @@ EXEMPT_FILES = make_set( "static/js/invite.js", "static/js/lightbox.js", "static/js/list_util.ts", + "static/js/list_widget.js", "static/js/loading.ts", "static/js/local_message.js", "static/js/localstorage.js",