mirror of https://github.com/zulip/zulip.git
message_list: Reorder and document properties of key classes.
This should help considerably in the readability of this part of the codebase; meanwhile, I also took the opportunity to note various TODOs where we might have something simple we can do to simplify these data structures or improve their interfaces.
This commit is contained in:
parent
9965ad2ea3
commit
8bd881c83f
|
@ -10,7 +10,24 @@ import {page_params} from "./page_params";
|
|||
import * as stream_data from "./stream_data";
|
||||
|
||||
export class MessageList {
|
||||
// A MessageList is the main interface for a message feed that is
|
||||
// rendered in the DOM. Code outside the message feed rendering
|
||||
// internals will directly call this module in order to manipulate
|
||||
// a message feed.
|
||||
//
|
||||
// Each MessageList has an associated MessageListData, which
|
||||
// manages the messages, and a MessageListView, which manages the
|
||||
// the templates/HTML rendering as well as invisible pagination.
|
||||
//
|
||||
// TODO: The abstraction boundary between this and MessageListView
|
||||
// is not particularly well-defined; it could be nice to figure
|
||||
// out a good rule.
|
||||
constructor(opts) {
|
||||
// The MessageListData keeps track of the actual sequence of
|
||||
// messages displayed by this MessageList. Most
|
||||
// configuration/logic questions in this module will be
|
||||
// answered by calling a function from the MessageListData,
|
||||
// its Filter, or its FetchStatus object.
|
||||
if (opts.data) {
|
||||
this.data = opts.data;
|
||||
} else {
|
||||
|
@ -22,12 +39,39 @@ export class MessageList {
|
|||
});
|
||||
}
|
||||
|
||||
const collapse_messages = this.data.filter.supports_collapsing_recipients();
|
||||
// The table_name is the outer HTML element for this message
|
||||
// list in the DOM.
|
||||
const table_name = opts.table_name;
|
||||
this.view = new MessageListView(this, table_name, collapse_messages);
|
||||
this.table_name = table_name;
|
||||
|
||||
// TODO: This property should likely just be inlined into
|
||||
// having the MessageListView code that needs to access it
|
||||
// query .data.filter directly.
|
||||
const collapse_messages = this.data.filter.supports_collapsing_recipients();
|
||||
|
||||
// The MessageListView object that is responsible for
|
||||
// maintaining this message feed's HTML representation in the
|
||||
// DOM.
|
||||
this.view = new MessageListView(this, table_name, collapse_messages);
|
||||
|
||||
// Whether this is a narrowed message list. The only message
|
||||
// list that is not is the home_msg_list global.
|
||||
//
|
||||
// TODO: It would probably be more readable to replace this
|
||||
// with another property with an inverted meaning, since
|
||||
// home_msg_list is the message list that is special/unique.
|
||||
this.narrowed = this.table_name === "zfilt";
|
||||
|
||||
// TODO: This appears to be unused and can be deleted.
|
||||
this.num_appends = 0;
|
||||
|
||||
// Keeps track of whether the user has done a UI interaction,
|
||||
// such as "Mark as unread", that should disable marking
|
||||
// messages as read until prevent_reading is called again.
|
||||
//
|
||||
// Distinct from filter.can_mark_messages_read(), which is a
|
||||
// property of the type of narrow, regardless of actions by
|
||||
// the user. Possibly this can be unified in some nice way.
|
||||
this.reading_prevented = false;
|
||||
|
||||
return this;
|
||||
|
|
|
@ -8,16 +8,51 @@ import * as user_topics from "./user_topics";
|
|||
import * as util from "./util";
|
||||
|
||||
export class MessageListData {
|
||||
// MessageListData is a core data structure for keeping track of a
|
||||
// contiguous block of messages matching a given narrow that can
|
||||
// be displayed in a Zulip message feed.
|
||||
//
|
||||
// See also MessageList and MessageListView, which are important
|
||||
// to actually display a message list.
|
||||
|
||||
constructor({excludes_muted_topics, filter = new Filter()}) {
|
||||
this.excludes_muted_topics = excludes_muted_topics;
|
||||
// The Filter object defines which messages match the narrow,
|
||||
// and defines most of the configuration for the MessageListData.
|
||||
this.filter = filter;
|
||||
|
||||
// The FetchStatus object keeps track of our understanding of
|
||||
// to what extent this MessageListData has all the messages
|
||||
// that the server possesses matching this narrow, and whether
|
||||
// we're in the progress of fetching more.
|
||||
this.fetch_status = new FetchStatus();
|
||||
|
||||
// _all_items is a sorted list of all message objects that
|
||||
// match this.filter, regardless of muting.
|
||||
//
|
||||
// Most code will instead use _items, which contains contains
|
||||
// only messages that should be displayed after excluding
|
||||
// muted topics and messages sent by muted users.
|
||||
this._all_items = [];
|
||||
this._items = [];
|
||||
this._hash = new Map();
|
||||
this._local_only = new Set();
|
||||
this._selected_id = -1;
|
||||
|
||||
this.filter = filter;
|
||||
this.fetch_status = new FetchStatus();
|
||||
// _hash contains the same messages as _all_items, mapped by
|
||||
// message ID. It's used to efficiently query if a given
|
||||
// message is present.
|
||||
this._hash = new Map();
|
||||
|
||||
// Some views exclude muted topics.
|
||||
//
|
||||
// TODO: Refactor this to be a property of Filter, rather than
|
||||
// a parameter that needs to be passed into the constructor..
|
||||
this.excludes_muted_topics = excludes_muted_topics;
|
||||
|
||||
// Tracks any locally echoed messages, which we know aren't present on the server.
|
||||
this._local_only = new Set();
|
||||
|
||||
// The currently selected message ID. The special value -1
|
||||
// there is no selected message. A common situation is when
|
||||
// there are no messages matching the current filter.
|
||||
this._selected_id = -1;
|
||||
}
|
||||
|
||||
all_messages() {
|
||||
|
|
|
@ -224,18 +224,51 @@ function populate_group_from_message_container(group, message_container) {
|
|||
}
|
||||
|
||||
export class MessageListView {
|
||||
// MessageListView is the module responsible for rendering a
|
||||
// MessageList into the DOM, and maintaining it over time.
|
||||
//
|
||||
// Logic to compute context, render templates, insert them into
|
||||
// the DOM, and generally
|
||||
|
||||
constructor(list, table_name, collapse_messages) {
|
||||
// The MessageList that this MessageListView is responsible for rendering.
|
||||
this.list = list;
|
||||
|
||||
// TODO: Access this via .list.data.
|
||||
this.collapse_messages = collapse_messages;
|
||||
|
||||
// These three data structures keep track of groups of messages in the DOM.
|
||||
//
|
||||
// The message_groups are blocks of messages rendered into the
|
||||
// DOM that will share a common recipent bar heading.
|
||||
//
|
||||
// A message_container an object containing a Message object
|
||||
// plus additional computed metadata needed for rendering it
|
||||
// in the DOM.
|
||||
//
|
||||
// _rows contains jQuery objects for the `message_row`
|
||||
// elements rendered by single_message.hbs.
|
||||
//
|
||||
// TODO: Consider renaming _message_groups to something like _recipient_groups.
|
||||
// TODO: Consider renaming _rows to something like $rows.
|
||||
this._rows = new Map();
|
||||
this.message_containers = new Map();
|
||||
this._message_groups = [];
|
||||
|
||||
// TODO: Should this be just accessing .list.table_name?
|
||||
this.table_name = table_name;
|
||||
if (this.table_name) {
|
||||
this.clear_table();
|
||||
}
|
||||
this._message_groups = [];
|
||||
|
||||
// Half-open interval of the indices that define the current render window
|
||||
// For performance reasons, this module renders at most
|
||||
// _RENDER_WINDOW_SIZE messages into the DOM at a time, and
|
||||
// will transparently adjust which messages are rendered
|
||||
// whenever the user scrolls within _RENDER_THRESHOLD of the
|
||||
// edge of the rendered window.
|
||||
//
|
||||
// These two values are a half-open interval keeping track of
|
||||
// what range of messages is currently rendered in the dOM.
|
||||
this._render_win_start = 0;
|
||||
this._render_win_end = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue