mirror of
https://github.com/zulip/zulip.git
synced 2025-11-22 15:31:20 +00:00
This commit was originally automatically generated using `tools/lint --only=eslint --fix`. It was then modified by tabbott to contain only changes to a set of files that are unlikely to result in significant merge conflicts with any open pull request, excluding about 20 files. His plan is to merge the remaining changes with more precise care, potentially involving merging parts of conflicting pull requests before running the `eslint --fix` operation. Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
337 lines
9.4 KiB
JavaScript
337 lines
9.4 KiB
JavaScript
const render_more_topics = require('../templates/more_topics.hbs');
|
|
const render_topic_list_item = require('../templates/topic_list_item.hbs');
|
|
const Dict = require('./dict').Dict;
|
|
|
|
/*
|
|
Track all active widgets with a Dict.
|
|
|
|
(We have at max one for now, but we may
|
|
eventually allow multiple streams to be
|
|
expanded.)
|
|
*/
|
|
|
|
const active_widgets = new Dict();
|
|
|
|
// We know whether we're zoomed or not.
|
|
let zoomed = false;
|
|
|
|
exports.remove_expanded_topics = function () {
|
|
stream_popover.hide_topic_popover();
|
|
|
|
_.each(active_widgets.values(), function (widget) {
|
|
widget.remove();
|
|
});
|
|
|
|
active_widgets.clear();
|
|
};
|
|
|
|
exports.close = function () {
|
|
zoomed = false;
|
|
exports.remove_expanded_topics();
|
|
};
|
|
|
|
exports.zoom_out = function () {
|
|
zoomed = false;
|
|
|
|
const stream_ids = active_widgets.keys();
|
|
|
|
if (stream_ids.length !== 1) {
|
|
blueslip.error('Unexpected number of topic lists to zoom out.');
|
|
return;
|
|
}
|
|
|
|
const stream_id = stream_ids[0];
|
|
const widget = active_widgets.get(stream_id);
|
|
const parent_widget = widget.get_parent();
|
|
|
|
exports.rebuild(parent_widget, stream_id);
|
|
};
|
|
|
|
function update_unread_count(unread_count_elem, count) {
|
|
// unread_count_elem is a jquery element...we expect DOM
|
|
// to look like this:
|
|
// <div class="topic-unread-count {{#if is_zero}}zero_count{{/if}}">
|
|
// <div class="value">{{unread}}</div>
|
|
// </div>
|
|
const value_span = unread_count_elem.find('.value');
|
|
|
|
if (value_span.length === 0) {
|
|
blueslip.error('malformed dom for unread count');
|
|
return;
|
|
}
|
|
|
|
if (count === 0) {
|
|
unread_count_elem.hide();
|
|
value_span.text('');
|
|
} else {
|
|
unread_count_elem.removeClass("zero_count");
|
|
unread_count_elem.show();
|
|
value_span.text(count);
|
|
}
|
|
}
|
|
|
|
exports.set_count = function (stream_id, topic, count) {
|
|
const widget = active_widgets.get(stream_id);
|
|
|
|
if (widget === undefined) {
|
|
return;
|
|
}
|
|
|
|
widget.set_count(topic, count);
|
|
};
|
|
|
|
exports.widget = function (parent_elem, my_stream_id) {
|
|
const self = {};
|
|
|
|
self.build_list = function () {
|
|
self.topic_items = new Dict({fold_case: true});
|
|
|
|
const max_topics = 5;
|
|
const topic_names = topic_data.get_recent_names(my_stream_id);
|
|
|
|
const ul = $('<ul class="topic-list">');
|
|
|
|
_.each(topic_names, function (topic_name, idx) {
|
|
const num_unread = unread.num_unread_for_topic(my_stream_id, topic_name);
|
|
|
|
if (!zoomed) {
|
|
// Show the most recent topics, as well as any with unread messages
|
|
const show_topic = idx < max_topics || num_unread > 0 ||
|
|
self.active_topic === topic_name.toLowerCase();
|
|
|
|
if (!show_topic) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const topic_info = {
|
|
topic_name: topic_name,
|
|
unread: num_unread,
|
|
is_zero: num_unread === 0,
|
|
is_muted: muting.is_topic_muted(my_stream_id, topic_name),
|
|
url: hash_util.by_stream_topic_uri(my_stream_id, topic_name),
|
|
};
|
|
const li = $(render_topic_list_item(topic_info));
|
|
self.topic_items.set(topic_name, li);
|
|
ul.append(li);
|
|
});
|
|
|
|
// Now, we decide whether we need to show the "more topics"
|
|
// widget. We need it if there are at least 5 topics in the
|
|
// frontend's cache, or if we (possibly) don't have all
|
|
// historical topics in the browser's cache.
|
|
const show_more = self.build_more_topics_section();
|
|
const sub = stream_data.get_sub_by_id(my_stream_id);
|
|
|
|
if (topic_names.length > max_topics || !stream_data.all_topics_in_cache(sub)) {
|
|
ul.append(show_more);
|
|
}
|
|
return ul;
|
|
};
|
|
|
|
self.build_more_topics_section = function () {
|
|
const show_more_html = render_more_topics();
|
|
return $(show_more_html);
|
|
};
|
|
|
|
self.get_parent = function () {
|
|
return parent_elem;
|
|
};
|
|
|
|
self.get_stream_id = function () {
|
|
return my_stream_id;
|
|
};
|
|
|
|
self.get_dom = function () {
|
|
return self.dom;
|
|
};
|
|
|
|
self.remove = function () {
|
|
self.dom.remove();
|
|
};
|
|
|
|
self.num_items = function () {
|
|
return self.topic_items.num_items();
|
|
};
|
|
|
|
self.set_count = function (topic, count) {
|
|
if (!self.topic_items.has(topic)) {
|
|
// This can happen for truncated topic lists. No need
|
|
// to warn about it.
|
|
return;
|
|
}
|
|
const topic_li = self.topic_items.get(topic);
|
|
const unread_count_elem = topic_li.find('.topic-unread-count').expectOne();
|
|
|
|
update_unread_count(unread_count_elem, count);
|
|
};
|
|
|
|
self.activate_topic = function () {
|
|
const li = self.topic_items.get(self.active_topic);
|
|
if (li) {
|
|
li.addClass('active-sub-filter');
|
|
}
|
|
};
|
|
|
|
self.show_spinner = function () {
|
|
// The spinner will go away once we get results and redraw
|
|
// the whole list.
|
|
const spinner = self.dom.find('.searching-for-more-topics');
|
|
spinner.show();
|
|
};
|
|
|
|
self.show_no_more_topics = function () {
|
|
const elem = self.dom.find('.no-more-topics-found');
|
|
elem.show();
|
|
self.no_more_topics = true;
|
|
};
|
|
|
|
self.build = function (active_topic, no_more_topics) {
|
|
self.no_more_topics = false; // for now
|
|
|
|
if (active_topic) {
|
|
active_topic = active_topic.toLowerCase();
|
|
}
|
|
self.active_topic = active_topic;
|
|
|
|
self.dom = self.build_list();
|
|
|
|
parent_elem.append(self.dom);
|
|
|
|
// We often rebuild an entire topic list, and the
|
|
// caller will pass us in no_more_topics as true
|
|
// if we were showing "No more topics found" from
|
|
// the initial zooming.
|
|
if (no_more_topics) {
|
|
self.show_no_more_topics();
|
|
}
|
|
|
|
if (active_topic) {
|
|
self.activate_topic();
|
|
}
|
|
};
|
|
|
|
return self;
|
|
};
|
|
|
|
exports.active_stream_id = function () {
|
|
const stream_ids = active_widgets.keys();
|
|
|
|
if (stream_ids.length !== 1) {
|
|
return;
|
|
}
|
|
|
|
return stream_ids[0];
|
|
};
|
|
|
|
exports.get_stream_li = function () {
|
|
const widgets = active_widgets.values();
|
|
|
|
if (widgets.length !== 1) {
|
|
return;
|
|
}
|
|
|
|
const stream_li = widgets[0].get_parent();
|
|
return stream_li;
|
|
};
|
|
|
|
exports.need_to_show_no_more_topics = function (stream_id) {
|
|
// This function is important, and the use case here is kind of
|
|
// subtle. We do complete redraws of the topic list when new
|
|
// messages come in, and we don't want to overwrite the
|
|
// "no more topics" error message.
|
|
if (!zoomed) {
|
|
return false;
|
|
}
|
|
|
|
if (!active_widgets.has(stream_id)) {
|
|
return false;
|
|
}
|
|
|
|
const widget = active_widgets.get(stream_id);
|
|
|
|
return widget.no_more_topics;
|
|
};
|
|
|
|
exports.rebuild = function (stream_li, stream_id) {
|
|
const active_topic = narrow_state.topic();
|
|
const no_more_topics = exports.need_to_show_no_more_topics(stream_id);
|
|
|
|
exports.remove_expanded_topics();
|
|
const widget = exports.widget(stream_li, stream_id);
|
|
widget.build(active_topic, no_more_topics);
|
|
|
|
active_widgets.set(stream_id, widget);
|
|
};
|
|
|
|
// For zooming, we only do topic-list stuff here...let stream_list
|
|
// handle hiding/showing the non-narrowed streams
|
|
exports.zoom_in = function () {
|
|
zoomed = true;
|
|
|
|
const stream_id = exports.active_stream_id();
|
|
if (!stream_id) {
|
|
blueslip.error('Cannot find widget for topic history zooming.');
|
|
return;
|
|
}
|
|
|
|
const active_widget = active_widgets.get(stream_id);
|
|
|
|
const before_count = active_widget.num_items();
|
|
|
|
function on_success() {
|
|
if (!active_widgets.has(stream_id)) {
|
|
blueslip.warn('User re-narrowed before topic history was returned.');
|
|
return;
|
|
}
|
|
|
|
if (!zoomed) {
|
|
blueslip.warn('User zoomed out before topic history was returned.');
|
|
// Note that we could attempt to re-draw the zoomed out topic list
|
|
// here, given that we have more history, but that might be more
|
|
// confusing than helpful to a user who is likely trying to browse
|
|
// other streams.
|
|
return;
|
|
}
|
|
|
|
const widget = active_widgets.get(stream_id);
|
|
|
|
exports.rebuild(widget.get_parent(), stream_id);
|
|
|
|
const after_count = widget.num_items();
|
|
|
|
if (after_count === before_count) {
|
|
widget.show_no_more_topics();
|
|
}
|
|
}
|
|
|
|
ui.get_scroll_element($('#stream-filters-container')).scrollTop(0);
|
|
active_widget.show_spinner();
|
|
topic_data.get_server_history(stream_id, on_success);
|
|
};
|
|
|
|
exports.initialize = function () {
|
|
$('#stream_filters').on('click', '.topic-box', function (e) {
|
|
if (e.metaKey || e.ctrlKey) {
|
|
return;
|
|
}
|
|
|
|
// In a more componentized world, we would delegate some
|
|
// of this stuff back up to our parents.
|
|
|
|
const stream_id = $(e.target).parents('.narrow-filter').attr('data-stream-id');
|
|
const sub = stream_data.get_sub_by_id(stream_id);
|
|
const topic = $(e.target).parents('li').attr('data-topic-name');
|
|
|
|
narrow.activate([
|
|
{operator: 'stream', operand: sub.name},
|
|
{operator: 'topic', operand: topic}],
|
|
{trigger: 'sidebar'});
|
|
|
|
e.preventDefault();
|
|
});
|
|
};
|
|
|
|
|
|
window.topic_list = exports;
|