diff --git a/frontend_tests/node_tests/recent_topics.js b/frontend_tests/node_tests/recent_topics.js index eb20c9e6cf..dec5d209cd 100644 --- a/frontend_tests/node_tests/recent_topics.js +++ b/frontend_tests/node_tests/recent_topics.js @@ -199,11 +199,20 @@ messages[9] = { function generate_topic_data(topic_info_array) { // Since most of the fields are common, this function helps generate fixtures // with non common fields. + $.clear_all_elements(); const data = []; - for (const [stream_id, topic, unread_count, hidden] of topic_info_array) { + for (const [stream_id, topic, unread_count, muted, participated] of topic_info_array) { + const topic_selector = $.create('#recent_topic:' + stream_id + ":" + topic); + topic_selector.data = function () { + return { + participated: participated, + muted: muted, + unreadCount: unread_count, + }; + }; + data.push({ count_senders: 0, - hidden: hidden, invite_only: false, is_web_public: true, last_msg_time: 'Just now', @@ -218,6 +227,8 @@ function generate_topic_data(topic_info_array) { topic: topic, topic_url: 'https://www.example.com', unread_count: unread_count, + muted: muted, + participated: participated, }); } return data; @@ -238,14 +249,14 @@ run_test("test_recent_topics_launch", () => { filter_participated: false, filter_unread: false, recent_topics: generate_topic_data([ - // stream_id, topic, unread_count, hidden - [1, 'topic-7', 1, true], - [1, 'topic-6', 1, false], - [1, 'topic-5', 1, false], - [1, 'topic-4', 1, false], - [1, 'topic-3', 1, false], - [1, 'topic-2', 1, false], - [1, 'topic-1', 0, false], + // stream_id, topic, unread_count, muted, participated + [1, 'topic-7', 1, true, true], + [1, 'topic-6', 1, false, true], + [1, 'topic-5', 1, false, true], + [1, 'topic-4', 1, false, false], + [1, 'topic-3', 1, false, false], + [1, 'topic-2', 1, false, true], + [1, 'topic-1', 0, false, true], ]), }; @@ -268,7 +279,7 @@ run_test("test_recent_topics_launch", () => { run_test('test_filter_all', () => { // Just tests inplace rerender of a message // in All topics filter. - let expected = generate_topic_data([[1, 'topic-1', 0, false]])[0]; + let expected = generate_topic_data([[1, 'topic-1', 0, false, true]])[0]; global.stub_templates(function (template_name, data) { assert.equal(template_name, 'recent_topic_row'); @@ -280,7 +291,7 @@ run_test('test_filter_all', () => { const rt = zrequire('recent_topics'); rt.process_messages([messages[0]]); - expected = generate_topic_data([[1, 'topic-7', 1, true]])[0]; + expected = generate_topic_data([[1, 'topic-7', 1, true, true]])[0]; // topic is muted (=== hidden) rt.process_messages([messages[9]]); @@ -292,14 +303,14 @@ run_test('test_filter_unread', () => { filter_participated: false, filter_unread: true, recent_topics: generate_topic_data([ - // stream_id, topic, unread_count, hidden - [1, 'topic-7', 1, true], - [1, 'topic-6', 1, false], - [1, 'topic-5', 1, false], - [1, 'topic-4', 1, false], - [1, 'topic-3', 1, false], - [1, 'topic-2', 1, false], - [1, 'topic-1', 0, true], + // stream_id, topic, unread_count, muted, participated + [1, 'topic-7', 1, true, true], + [1, 'topic-6', 1, false, true], + [1, 'topic-5', 1, false, true], + [1, 'topic-4', 1, false, false], + [1, 'topic-3', 1, false, false], + [1, 'topic-2', 1, false, true], + [1, 'topic-1', 0, false, true], ]), }; @@ -320,7 +331,6 @@ run_test('test_filter_unread', () => { // Unselect "unread" filter by clicking twice. expected.filter_unread = false; - expected.recent_topics[6].hidden = false; rt.set_filter('unread'); // Now clicking "all" filter should have no change to expected data. @@ -333,14 +343,14 @@ run_test('test_filter_participated', () => { filter_participated: true, filter_unread: false, recent_topics: generate_topic_data([ - // stream_id, topic, unread_count, hidden - [1, 'topic-7', 1, true], - [1, 'topic-6', 1, false], - [1, 'topic-5', 1, false], - [1, 'topic-4', 1, true], - [1, 'topic-3', 1, true], - [1, 'topic-2', 1, false], - [1, 'topic-1', 0, false], + // stream_id, topic, unread_count, muted, participated + [1, 'topic-7', 1, true, true], + [1, 'topic-6', 1, false, true], + [1, 'topic-5', 1, false, true], + [1, 'topic-4', 1, false, false], + [1, 'topic-3', 1, false, false], + [1, 'topic-2', 1, false, true], + [1, 'topic-1', 0, false, true], ]), }; @@ -359,8 +369,6 @@ run_test('test_filter_participated', () => { }); rt.set_filter('participated'); - expected.recent_topics[3].hidden = false; - expected.recent_topics[4].hidden = false; expected.filter_participated = false; rt.set_filter('all'); }); @@ -492,6 +500,14 @@ run_test('test_topic_edit', () => { verify_topic_data(all_topics, stream1, topic6, messages[8].id, true); assert.equal(all_topics.get(stream1 + ":" + topic8), undefined); + let topic_selector = $.create('#recent_topic:' + stream1 + ":" + topic8); + topic_selector.data = function () { + return { + participated: true, + muted: false, + unreadCount: 1, + }; + }; // change topic of topic6 to topic8 messages[7].topic = topic8; messages[8].topic = topic8; @@ -505,6 +521,14 @@ run_test('test_topic_edit', () => { verify_topic_data(all_topics, stream1, topic1, messages[0].id, true); assert.equal(all_topics.get(stream2 + ":" + topic1), undefined); + topic_selector = $.create('#recent_topic:' + stream2 + ":" + topic1); + topic_selector.data = function () { + return { + participated: true, + muted: false, + unreadCount: 0, + }; + }; messages[0].stream_id = stream2; rt.process_topic_edit(stream1, topic1, topic1, stream2); all_topics = rt.get(); @@ -516,6 +540,14 @@ run_test('test_topic_edit', () => { verify_topic_data(all_topics, stream2, topic1, messages[0].id, true); assert.equal(all_topics.get(stream3 + ":" + topic9), undefined); + topic_selector = $.create('#recent_topic:' + stream3 + ":" + topic9); + topic_selector.data = function () { + return { + participated: false, + muted: false, + unreadCount: 1, + }; + }; messages[0].stream_id = stream3; messages[0].topic = topic9; rt.process_topic_edit(stream2, topic1, topic9, stream3); diff --git a/static/js/click_handlers.js b/static/js/click_handlers.js index cc0ad8ad33..5917849fe8 100644 --- a/static/js/click_handlers.js +++ b/static/js/click_handlers.js @@ -358,25 +358,12 @@ exports.initialize = function () { $('body').on('click', '.btn-recent-filters', function (e) { e.stopPropagation(); recent_topics.set_filter(e.currentTarget.dataset.filter); + recent_topics.update_filters_view(); }); // Search for all table rows (this combines stream & topic names) $('body').on('keyup', '#recent_topics_search', _.debounce(function () { - // take all rows and slice off the header. - const $rows = $('.recent_topics_table tr').slice(1); - // split the search text around whitespace(s). - // eg: "Denamark recent" -> ["Denamrk", "recent"] - const search_keywords = $.trim($(this).val()).split(/\s+/); - // turn the search keywords into word boundry groups - // eg: ["Denamrk", "recent"] -> "^(?=.*\bDenmark\b)(?=.*\brecent\b).*$" - const val = '^(?=.*\\b' + search_keywords.join('\\b)(?=.*\\b') + ').*$'; - const reg = RegExp(val, 'i'); // i for ignorecase - let text; - - $rows.show().filter(function () { - text = $(this).text().replace(/\s+/g, ' '); - return !reg.test(text); - }).hide(); + recent_topics.update_filters_view(); // Wait for user to go idle before initiating search. }, 300)); diff --git a/static/js/recent_topics.js b/static/js/recent_topics.js index dd0a46d9d1..4e76cea396 100644 --- a/static/js/recent_topics.js +++ b/static/js/recent_topics.js @@ -1,5 +1,6 @@ const render_recent_topics_body = require('../templates/recent_topics_table.hbs'); const render_recent_topic_row = require('../templates/recent_topic_row.hbs'); +const render_recent_topics_filters = require('../templates/recent_topics_filters.hbs'); const topics = new Map(); // Key is stream-id:topic. // Sets the number of avatars to display. // Rest of the avatars, if present, are displayed as {+x} @@ -84,14 +85,11 @@ function format_topic(topic_data) { const last_msg_time = timerender.last_seen_status_from_date(time); // We hide the row according to filters or if it's muted. - let hidden = muting.is_topic_muted(stream_id, topic); + // We only supply the data to the topic rows and let jquery + // display / hide them according to filters instead of + // doing complete re-render. + const muted = !!muting.is_topic_muted(stream_id, topic); const unread_count = unread.unread_topic_counter.get(stream_id, topic); - if (unread_count === 0 && filters.has('unread')) { - hidden = true; - } - if (!topic_data.participated && filters.has('participated')) { - hidden = true; - } // Display in most recent sender first order const all_senders = recent_senders.get_topic_recent_senders(stream_id, topic); @@ -111,9 +109,10 @@ function format_topic(topic_data) { unread_count: unread_count, last_msg_time: last_msg_time, topic_url: hash_util.by_stream_topic_uri(stream_id, topic), - hidden: hidden, senders: senders_info, count_senders: Math.max(0, all_senders.length - MAX_AVATAR), + muted: muted, + participated: topic_data.participated, }; } @@ -144,6 +143,18 @@ exports.process_topic_edit = function (old_stream_id, old_topic, new_topic, new_ exports.process_messages(new_topic_msgs); }; +function is_row_hidden(data) { + const {participated, muted, unreadCount} = data; + if (unreadCount === 0 && filters.has('unread')) { + return true; + } else if (!participated && filters.has('participated')) { + return true; + } else if (muted) { + return true; + } + return false; +} + exports.inplace_rerender = function (topic_key) { // We remove topic from the UI and reinsert it. // This makes sure we maintain the correct order @@ -153,7 +164,7 @@ exports.inplace_rerender = function (topic_key) { return false; } const formatted_values = format_topic(topic_data); - const topic_row = get_topic_row(topic_key); + let topic_row = get_topic_row(topic_key); topic_row.remove(); const rendered_row = render_recent_topic_row(formatted_values); @@ -176,6 +187,13 @@ exports.inplace_rerender = function (topic_key) { get_topic_row(sorted_topic_keys[1]).before(rendered_row); } get_topic_row(sorted_topic_keys[topic_index - 1]).after(rendered_row); + + topic_row = get_topic_row(topic_key); + if (is_row_hidden(topic_row.data())) { + topic_row.hide(); + } else { + topic_row.show(); + } }; exports.update_topic_is_muted = function (stream_id, topic, is_muted) { @@ -210,7 +228,63 @@ exports.set_filter = function (filter) { } else { filters.add(filter); } - exports.complete_rerender(); +}; + +function show_selected_filters() { + if (filters.size === 0) { + $('#recent_topics_filter_buttons') + .find('[data-filter="all"]') + .addClass('btn-recent-selected'); + } else { + for (const filter of filters) { + $('#recent_topics_filter_buttons') + .find('[data-filter="' + filter + '"]') + .addClass('btn-recent-selected'); + } + } +} + +exports.update_filters_view = function () { + const $rows = $('.recent_topics_table tr').slice(1); + const search_val = $('#recent_topics_search').val(); + $rows.each(function () { + const row = $(this); + if (is_row_hidden(row.data())) { + row.hide(); + } else { + row.show(); + } + }); + exports.search_keyword(search_val); + + const rendered_filters = render_recent_topics_filters({ + filter_participated: filters.has('participated'), + filter_unread: filters.has('unread'), + }); + $("#recent_filters_group").html(rendered_filters); + + show_selected_filters(); +}; + +exports.search_keyword = function (keyword) { + if (keyword === "") { + return false; + } + // take all rows and slice off the header. + const $rows = $('.recent_topics_table tr').slice(1); + // split the search text around whitespace(s). + // eg: "Denamark recent" -> ["Denamrk", "recent"] + const search_keywords = $.trim(keyword).split(/\s+/); + // turn the search keywords into word boundry groups + // eg: ["Denamrk", "recent"] -> "^(?=.*\bDenmark\b)(?=.*\brecent\b).*$" + const val = '^(?=.*\\b' + search_keywords.join('\\b)(?=.*\\b') + ').*$'; + const reg = RegExp(val, 'i'); // i for ignorecase + let text; + + $rows.filter(function () { + text = $(this).text().replace(/\s+/g, ' '); + return !reg.test(text); + }).hide(); }; exports.complete_rerender = function () { @@ -223,18 +297,7 @@ exports.complete_rerender = function () { filter_unread: filters.has('unread'), }); $('#recent_topics_table').html(rendered_body); - - if (filters.size === 0) { - $('#recent_topics_filter_buttons') - .find('[data-filter="all"]') - .addClass('btn-recent-selected'); - } else { - for (const filter of filters) { - $('#recent_topics_filter_buttons') - .find('[data-filter="' + filter + '"]') - .addClass('btn-recent-selected'); - } - } + show_selected_filters(); }; exports.launch = function () { diff --git a/static/templates/recent_topic_row.hbs b/static/templates/recent_topic_row.hbs index aae5d319e7..9e442240f1 100644 --- a/static/templates/recent_topic_row.hbs +++ b/static/templates/recent_topic_row.hbs @@ -1,4 +1,4 @@ - + {{> stream_privacy }} diff --git a/static/templates/recent_topics_filters.hbs b/static/templates/recent_topics_filters.hbs new file mode 100644 index 0000000000..a34de546f2 --- /dev/null +++ b/static/templates/recent_topics_filters.hbs @@ -0,0 +1,17 @@ + + + diff --git a/static/templates/recent_topics_table.hbs b/static/templates/recent_topics_table.hbs index 477f75a068..82a60f517b 100644 --- a/static/templates/recent_topics_table.hbs +++ b/static/templates/recent_topics_table.hbs @@ -1,21 +1,7 @@
- - - +
+ {{> recent_topics_filters}} +