2021-02-28 21:31:33 +01:00
|
|
|
import autosize from "autosize";
|
2020-08-01 03:43:15 +02:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
import {MessageListData} from "./message_list_data";
|
|
|
|
import {MessageListView} from "./message_list_view";
|
|
|
|
import * as narrow_state from "./narrow_state";
|
|
|
|
import * as stream_data from "./stream_data";
|
2019-07-16 20:19:11 +02:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
export let narrowed;
|
2021-02-24 05:00:56 +01:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
export function set_narrowed(value) {
|
|
|
|
narrowed = value;
|
|
|
|
}
|
2016-04-25 23:45:25 +02:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
export class MessageList {
|
2020-07-23 00:25:12 +02:00
|
|
|
constructor(opts) {
|
|
|
|
if (opts.data) {
|
2021-01-25 06:23:16 +01:00
|
|
|
this.excludes_muted_topics = opts.data.excludes_muted_topics;
|
2020-07-23 00:25:12 +02:00
|
|
|
this.data = opts.data;
|
|
|
|
} else {
|
|
|
|
const filter = opts.filter;
|
|
|
|
|
2021-01-25 06:23:16 +01:00
|
|
|
this.excludes_muted_topics = opts.excludes_muted_topics;
|
2020-07-23 00:25:12 +02:00
|
|
|
this.data = new MessageListData({
|
2021-01-25 06:23:16 +01:00
|
|
|
excludes_muted_topics: this.excludes_muted_topics,
|
2020-07-23 00:25:12 +02:00
|
|
|
filter,
|
|
|
|
});
|
|
|
|
}
|
2013-02-26 23:30:13 +01:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
opts.collapse_messages = true;
|
2018-05-14 12:39:34 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
const collapse_messages = opts.collapse_messages;
|
|
|
|
const table_name = opts.table_name;
|
|
|
|
this.view = new MessageListView(this, table_name, collapse_messages);
|
|
|
|
this.table_name = table_name;
|
|
|
|
this.narrowed = this.table_name === "zfilt";
|
|
|
|
this.num_appends = 0;
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_messages(messages, opts) {
|
2018-05-14 12:39:34 +02:00
|
|
|
// This adds all messages to our data, but only returns
|
|
|
|
// the currently viewable ones.
|
2019-11-02 00:06:25 +01:00
|
|
|
const info = this.data.add_messages(messages);
|
2018-05-14 12:39:34 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const top_messages = info.top_messages;
|
|
|
|
const bottom_messages = info.bottom_messages;
|
|
|
|
const interior_messages = info.interior_messages;
|
2013-09-22 16:41:33 +02:00
|
|
|
|
message scrolling: Fix "Scroll down to view" warning.
We recently added a feature to warn users that they
may need to scroll down to view messages that they
just sent, but it was broken due to various complexities
in the rendering code path.
Now we compute it a bit more rigorously.
It requires us to pass some info about rendering up
and down the stack, which is why it's kind of a long
commit, but the bulk of the logic is in these JS files:
* message_list_view.js
* notifications.js
I choose to pass structs around instead of booleans,
because I anticipate we may eventually add more metadata
about rendering to it, plus bools are just kinda brittle.
(The exceptions are that `_maybe_autoscroll`, which
is at the bottom of the stack, just passes back a simple
boolean, and `notify_local_mixes`, also at the bottom
of the stack, just accepts a simple boolean.)
This errs on the side of warning the user, even if the
new message is partially visible.
Fixes #11138
2019-01-07 21:00:03 +01:00
|
|
|
// Currently we only need data back from rendering to
|
|
|
|
// tell us whether users needs to scroll, which only
|
|
|
|
// applies for `append_to_view`, but this may change over
|
|
|
|
// time.
|
2019-11-02 00:06:25 +01:00
|
|
|
let render_info;
|
message scrolling: Fix "Scroll down to view" warning.
We recently added a feature to warn users that they
may need to scroll down to view messages that they
just sent, but it was broken due to various complexities
in the rendering code path.
Now we compute it a bit more rigorously.
It requires us to pass some info about rendering up
and down the stack, which is why it's kind of a long
commit, but the bulk of the logic is in these JS files:
* message_list_view.js
* notifications.js
I choose to pass structs around instead of booleans,
because I anticipate we may eventually add more metadata
about rendering to it, plus bools are just kinda brittle.
(The exceptions are that `_maybe_autoscroll`, which
is at the bottom of the stack, just passes back a simple
boolean, and `notify_local_mixes`, also at the bottom
of the stack, just accepts a simple boolean.)
This errs on the side of warning the user, even if the
new message is partially visible.
Fixes #11138
2019-01-07 21:00:03 +01:00
|
|
|
|
2013-09-22 16:41:33 +02:00
|
|
|
if (interior_messages.length > 0) {
|
2020-07-23 00:25:12 +02:00
|
|
|
this.view.rerender_preserving_scrolltop(true);
|
2013-09-22 16:41:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (top_messages.length > 0) {
|
2020-07-23 00:25:12 +02:00
|
|
|
this.view.prepend(top_messages);
|
2013-09-22 16:41:33 +02:00
|
|
|
}
|
2018-05-04 12:44:28 +02:00
|
|
|
|
2013-09-22 16:41:33 +02:00
|
|
|
if (bottom_messages.length > 0) {
|
2020-07-23 00:25:12 +02:00
|
|
|
render_info = this.append_to_view(bottom_messages, opts);
|
2013-09-22 16:41:33 +02:00
|
|
|
}
|
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
if (this === narrowed && !this.empty()) {
|
2013-09-22 16:41:33 +02:00
|
|
|
// If adding some new messages to the message tables caused
|
|
|
|
// our current narrow to no longer be empty, hide the empty
|
|
|
|
// feed placeholder text.
|
|
|
|
narrow.hide_empty_narrow_message();
|
2014-03-04 22:39:34 +01:00
|
|
|
}
|
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
if (this === narrowed && !this.empty() && this.selected_id() === -1) {
|
2013-09-22 16:41:33 +02:00
|
|
|
// And also select the newly arrived message.
|
2020-07-23 00:25:12 +02:00
|
|
|
this.select_id(this.selected_id(), {then_scroll: true, use_closest: true});
|
2013-09-22 16:41:33 +02:00
|
|
|
}
|
message scrolling: Fix "Scroll down to view" warning.
We recently added a feature to warn users that they
may need to scroll down to view messages that they
just sent, but it was broken due to various complexities
in the rendering code path.
Now we compute it a bit more rigorously.
It requires us to pass some info about rendering up
and down the stack, which is why it's kind of a long
commit, but the bulk of the logic is in these JS files:
* message_list_view.js
* notifications.js
I choose to pass structs around instead of booleans,
because I anticipate we may eventually add more metadata
about rendering to it, plus bools are just kinda brittle.
(The exceptions are that `_maybe_autoscroll`, which
is at the bottom of the stack, just passes back a simple
boolean, and `notify_local_mixes`, also at the bottom
of the stack, just accepts a simple boolean.)
This errs on the side of warning the user, even if the
new message is partially visible.
Fixes #11138
2019-01-07 21:00:03 +01:00
|
|
|
|
|
|
|
return render_info;
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-09-22 16:41:33 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
get(id) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.get(id);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
num_items() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.num_items();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-16 17:10:22 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
empty() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.empty();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
first() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.first();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
last() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.last();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
prev() {
|
2018-05-26 12:29:38 +02:00
|
|
|
return this.data.prev();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-26 12:29:38 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
next() {
|
2018-05-26 12:29:38 +02:00
|
|
|
return this.data.next();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-26 12:29:38 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
is_at_end() {
|
2018-05-29 00:18:27 +02:00
|
|
|
return this.data.is_at_end();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-29 00:18:27 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
nth_most_recent_id(n) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.nth_most_recent_id(n);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-14 23:04:24 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
is_search() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.is_search();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-04 18:51:09 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
can_mark_messages_read() {
|
2019-07-10 02:03:41 +02:00
|
|
|
return this.data.can_mark_messages_read();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2019-07-10 02:03:41 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
clear(opts) {
|
2020-07-16 22:40:18 +02:00
|
|
|
opts = {clear_selected_id: true, ...opts};
|
2013-02-22 20:48:31 +01:00
|
|
|
|
2018-05-04 12:44:28 +02:00
|
|
|
this.data.clear();
|
2013-08-16 17:10:22 +02:00
|
|
|
this.view.clear_rendering_state(true);
|
2013-02-22 20:48:31 +01:00
|
|
|
|
|
|
|
if (opts.clear_selected_id) {
|
2018-05-04 12:44:28 +02:00
|
|
|
this.data.clear_selected_id();
|
2013-02-22 20:48:31 +01:00
|
|
|
}
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-02-22 20:48:31 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
selected_id() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.selected_id();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-02-20 18:26:50 +01:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
select_id(id, opts) {
|
2020-02-09 04:15:38 +01:00
|
|
|
opts = {
|
2018-05-06 21:43:17 +02:00
|
|
|
then_scroll: false,
|
|
|
|
target_scroll_offset: undefined,
|
|
|
|
use_closest: false,
|
|
|
|
empty_ok: false,
|
|
|
|
mark_read: true,
|
|
|
|
force_rerender: false,
|
2020-02-09 04:15:38 +01:00
|
|
|
...opts,
|
2020-07-20 22:18:43 +02:00
|
|
|
id,
|
2018-05-06 21:43:17 +02:00
|
|
|
msg_list: this,
|
2020-09-13 18:29:24 +02:00
|
|
|
previously_selected_id: this.data.selected_id(),
|
2020-02-09 04:15:38 +01:00
|
|
|
};
|
2013-07-03 19:15:07 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
const convert_id = (str_id) => {
|
2020-10-07 09:17:30 +02:00
|
|
|
const id = Number.parseFloat(str_id);
|
|
|
|
if (Number.isNaN(id)) {
|
2020-10-07 11:51:57 +02:00
|
|
|
throw new TypeError("Bad message id " + str_id);
|
2017-03-27 19:26:30 +02:00
|
|
|
}
|
|
|
|
return id;
|
2020-07-23 00:25:12 +02:00
|
|
|
};
|
2013-08-07 20:28:50 +02:00
|
|
|
|
2017-03-27 19:26:30 +02:00
|
|
|
id = convert_id(id);
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const closest_id = this.closest_id(id);
|
2013-09-27 21:18:54 +02:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let error_data;
|
2017-06-15 23:46:41 +02:00
|
|
|
|
2013-09-27 21:18:54 +02:00
|
|
|
// The name "use_closest" option is a bit legacy. We
|
|
|
|
// are always gonna move to the closest visible id; the flag
|
|
|
|
// just says whether we call blueslip.error or not. The caller
|
|
|
|
// sets use_closest to true when it expects us to move the
|
|
|
|
// pointer as needed, so only generate an error if the flag is
|
|
|
|
// false.
|
|
|
|
if (!opts.use_closest && closest_id !== id) {
|
2017-06-15 23:46:41 +02:00
|
|
|
error_data = {
|
2017-06-15 22:33:38 +02:00
|
|
|
table_name: this.table_name,
|
2020-07-20 22:18:43 +02:00
|
|
|
id,
|
|
|
|
closest_id,
|
2017-06-15 22:33:38 +02:00
|
|
|
};
|
2020-07-15 00:34:28 +02:00
|
|
|
blueslip.error("Selected message id not in MessageList", error_data);
|
2013-02-20 18:33:04 +01:00
|
|
|
}
|
2013-03-13 18:48:02 +01:00
|
|
|
|
2013-12-18 19:06:55 +01:00
|
|
|
if (closest_id === -1 && !opts.empty_ok) {
|
2017-06-15 23:46:41 +02:00
|
|
|
error_data = {
|
2013-12-02 21:40:49 +01:00
|
|
|
table_name: this.table_name,
|
2020-07-20 22:18:43 +02:00
|
|
|
id,
|
2018-05-04 12:44:28 +02:00
|
|
|
items_length: this.data.num_items(),
|
2013-12-02 21:40:49 +01:00
|
|
|
};
|
2020-09-24 07:56:29 +02:00
|
|
|
throw new Error("Cannot select id -1", error_data);
|
2013-10-30 18:38:16 +01:00
|
|
|
}
|
|
|
|
|
2013-09-27 21:18:54 +02:00
|
|
|
id = closest_id;
|
|
|
|
opts.id = id;
|
2018-05-04 12:44:28 +02:00
|
|
|
this.data.set_selected_id(id);
|
2013-09-27 21:18:54 +02:00
|
|
|
|
2014-01-22 22:20:36 +01:00
|
|
|
if (opts.force_rerender) {
|
|
|
|
this.rerender();
|
|
|
|
} else if (!opts.from_rendering) {
|
2013-08-16 17:10:22 +02:00
|
|
|
this.view.maybe_rerender();
|
2013-07-03 19:53:27 +02:00
|
|
|
}
|
2013-03-04 20:22:09 +01:00
|
|
|
|
2020-12-11 04:26:23 +01:00
|
|
|
$(document).trigger(new $.Event("message_selected.zulip", opts));
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-02-20 18:33:04 +01:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
reselect_selected_id() {
|
2018-05-04 12:44:28 +02:00
|
|
|
this.select_id(this.data.selected_id(), {from_rendering: true});
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-16 17:10:22 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
selected_message() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.get(this.data.selected_id());
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-02-14 23:48:37 +01:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
selected_row() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.get_row(this.data.selected_id());
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-02-20 00:49:21 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
closest_id(id) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.closest_id(id);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-07-24 22:33:06 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
advance_past_messages(msg_ids) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.advance_past_messages(msg_ids);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
selected_idx() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.selected_idx();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-04-10 18:30:36 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
subscribed_bookend_content(stream_name) {
|
2020-07-15 00:34:28 +02:00
|
|
|
return i18n.t("You subscribed to stream __stream__", {stream: stream_name});
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2014-02-05 16:55:24 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
unsubscribed_bookend_content(stream_name) {
|
2020-07-15 00:34:28 +02:00
|
|
|
return i18n.t("You unsubscribed from stream __stream__", {stream: stream_name});
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2014-02-05 16:55:24 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
not_subscribed_bookend_content(stream_name) {
|
2020-07-15 00:34:28 +02:00
|
|
|
return i18n.t("You are not subscribed to stream __stream__", {stream: stream_name});
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2014-02-05 16:55:24 +01:00
|
|
|
|
2020-08-22 23:29:23 +02:00
|
|
|
deactivated_bookend_content() {
|
|
|
|
return i18n.t("This stream has been deactivated");
|
|
|
|
}
|
|
|
|
|
2013-04-10 23:38:30 +02:00
|
|
|
// Maintains a trailing bookend element explaining any changes in
|
|
|
|
// your subscribed/unsubscribed status at the bottom of the
|
|
|
|
// message list.
|
2020-07-23 00:25:12 +02:00
|
|
|
update_trailing_bookend() {
|
2013-08-16 17:10:22 +02:00
|
|
|
this.view.clear_trailing_bookend();
|
2013-04-10 23:38:30 +02:00
|
|
|
if (!this.narrowed) {
|
|
|
|
return;
|
|
|
|
}
|
2019-11-02 00:06:25 +01:00
|
|
|
const stream_name = narrow_state.stream();
|
2017-09-15 10:55:40 +02:00
|
|
|
if (stream_name === undefined) {
|
2013-04-10 23:38:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-11-02 00:06:25 +01:00
|
|
|
let trailing_bookend_content;
|
|
|
|
let show_button = true;
|
|
|
|
const subscribed = stream_data.is_subscribed(stream_name);
|
2020-08-22 23:29:23 +02:00
|
|
|
const sub = stream_data.get_sub(stream_name);
|
|
|
|
if (sub === undefined) {
|
|
|
|
trailing_bookend_content = this.deactivated_bookend_content();
|
|
|
|
// Hide the resubscribe button for streams that no longer exist.
|
|
|
|
show_button = false;
|
|
|
|
} else if (subscribed) {
|
2017-09-15 10:55:40 +02:00
|
|
|
trailing_bookend_content = this.subscribed_bookend_content(stream_name);
|
2013-04-10 23:38:30 +02:00
|
|
|
} else {
|
|
|
|
if (!this.last_message_historical) {
|
2017-09-15 10:55:40 +02:00
|
|
|
trailing_bookend_content = this.unsubscribed_bookend_content(stream_name);
|
2017-06-21 02:20:33 +02:00
|
|
|
|
2020-08-22 23:29:23 +02:00
|
|
|
// For invite only streams hide the resubscribe button
|
2018-10-31 19:28:02 +01:00
|
|
|
// Hide button for guest users
|
2020-08-22 23:29:23 +02:00
|
|
|
show_button = !page_params.is_guest && !sub.invite_only;
|
2013-04-10 23:38:30 +02:00
|
|
|
} else {
|
2017-09-15 10:55:40 +02:00
|
|
|
trailing_bookend_content = this.not_subscribed_bookend_content(stream_name);
|
2013-04-10 23:38:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (trailing_bookend_content !== undefined) {
|
2017-06-21 02:20:33 +02:00
|
|
|
this.view.render_trailing_bookend(trailing_bookend_content, subscribed, show_button);
|
2013-04-10 23:38:30 +02:00
|
|
|
}
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-04-10 23:38:30 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
unmuted_messages(messages) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.unmuted_messages(messages);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-09-19 00:43:59 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
append(messages, opts) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const viewable_messages = this.data.append(messages);
|
2018-05-13 23:03:16 +02:00
|
|
|
this.append_to_view(viewable_messages, opts);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-13 23:03:16 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
append_to_view(messages, opts) {
|
2020-07-16 22:40:18 +02:00
|
|
|
opts = {messages_are_new: false, ...opts};
|
2013-08-14 23:48:28 +02:00
|
|
|
|
|
|
|
this.num_appends += 1;
|
2019-11-02 00:06:25 +01:00
|
|
|
const render_info = this.view.append(messages, opts.messages_are_new);
|
message scrolling: Fix "Scroll down to view" warning.
We recently added a feature to warn users that they
may need to scroll down to view messages that they
just sent, but it was broken due to various complexities
in the rendering code path.
Now we compute it a bit more rigorously.
It requires us to pass some info about rendering up
and down the stack, which is why it's kind of a long
commit, but the bulk of the logic is in these JS files:
* message_list_view.js
* notifications.js
I choose to pass structs around instead of booleans,
because I anticipate we may eventually add more metadata
about rendering to it, plus bools are just kinda brittle.
(The exceptions are that `_maybe_autoscroll`, which
is at the bottom of the stack, just passes back a simple
boolean, and `notify_local_mixes`, also at the bottom
of the stack, just accepts a simple boolean.)
This errs on the side of warning the user, even if the
new message is partially visible.
Fixes #11138
2019-01-07 21:00:03 +01:00
|
|
|
return render_info;
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2012-12-05 23:54:49 +01:00
|
|
|
|
2020-11-12 22:03:45 +01:00
|
|
|
remove_and_rerender(message_ids) {
|
|
|
|
this.data.remove(message_ids);
|
2014-02-25 22:45:11 +01:00
|
|
|
this.rerender();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-12-17 20:50:11 +01:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
show_edit_message(row, edit_obj) {
|
2020-05-21 12:23:29 +02:00
|
|
|
if (row.find(".message_edit_form form").length !== 0) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-16 13:48:22 +02:00
|
|
|
row.find(".message_edit_form").append(edit_obj.form);
|
2018-12-29 20:24:59 +01:00
|
|
|
row.find(".message_content, .status-message, .message_controls").hide();
|
2017-09-11 01:35:14 +02:00
|
|
|
row.find(".message_edit").css("display", "block");
|
2019-07-16 20:19:11 +02:00
|
|
|
autosize(row.find(".message_edit_content"));
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-05-15 00:22:16 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
hide_edit_message(row) {
|
2018-12-29 20:24:59 +01:00
|
|
|
row.find(".message_content, .status-message, .message_controls").show();
|
2020-04-16 13:48:22 +02:00
|
|
|
row.find(".message_edit_form").empty();
|
2013-05-15 00:22:16 +02:00
|
|
|
row.find(".message_edit").hide();
|
2017-06-15 18:15:09 +02:00
|
|
|
row.trigger("mouseleave");
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-05-15 00:22:16 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
show_edit_topic_on_recipient_row(recipient_row, form) {
|
2020-04-16 13:48:22 +02:00
|
|
|
recipient_row.find(".topic_edit_form").append(form);
|
2020-07-15 01:29:15 +02:00
|
|
|
recipient_row.find(".on_hover_topic_edit").hide();
|
|
|
|
recipient_row.find(".edit_content_button").hide();
|
2013-08-16 23:45:13 +02:00
|
|
|
recipient_row.find(".stream_topic").hide();
|
|
|
|
recipient_row.find(".topic_edit").show();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-16 23:45:13 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
hide_edit_topic_on_recipient_row(recipient_row) {
|
2013-08-16 23:45:13 +02:00
|
|
|
recipient_row.find(".stream_topic").show();
|
2020-07-15 01:29:15 +02:00
|
|
|
recipient_row.find(".on_hover_topic_edit").show();
|
|
|
|
recipient_row.find(".edit_content_button").show();
|
2020-04-16 13:48:22 +02:00
|
|
|
recipient_row.find(".topic_edit_form").empty();
|
2013-08-16 23:45:13 +02:00
|
|
|
recipient_row.find(".topic_edit").hide();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-16 23:45:13 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
show_message_as_read(message, options) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const row = this.get_row(message.id);
|
2020-07-15 01:29:15 +02:00
|
|
|
if (options.from === "pointer" || options.from === "server") {
|
|
|
|
row.find(".unread_marker").addClass("fast_fade");
|
2013-07-26 17:19:13 +02:00
|
|
|
} else {
|
2020-07-15 01:29:15 +02:00
|
|
|
row.find(".unread_marker").addClass("slow_fade");
|
2013-07-26 17:19:13 +02:00
|
|
|
}
|
2020-07-15 01:29:15 +02:00
|
|
|
row.removeClass("unread");
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-07-01 23:28:27 +02:00
|
|
|
|
2020-07-26 18:37:01 +02:00
|
|
|
rerender_view() {
|
|
|
|
this.view.rerender_preserving_scrolltop();
|
|
|
|
this.redo_selection();
|
|
|
|
}
|
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
rerender() {
|
2013-05-14 21:18:11 +02:00
|
|
|
// We need to clear the rendering state, rather than just
|
2013-08-16 17:10:22 +02:00
|
|
|
// doing clear_table, since we want to potentially recollapse
|
2013-05-14 21:18:11 +02:00
|
|
|
// things.
|
2018-05-04 12:44:28 +02:00
|
|
|
this.data.reset_select_to_closest();
|
2013-08-16 17:10:22 +02:00
|
|
|
this.view.clear_rendering_state(false);
|
|
|
|
this.view.update_render_window(this.selected_idx(), false);
|
2018-04-14 00:36:14 +02:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
if (this === narrowed) {
|
2018-04-14 00:36:14 +02:00
|
|
|
if (this.empty()) {
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
} else {
|
|
|
|
narrow.hide_empty_narrow_message();
|
|
|
|
}
|
|
|
|
}
|
2020-07-26 18:37:01 +02:00
|
|
|
this.rerender_view();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2018-05-04 12:44:28 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
redo_selection() {
|
2019-11-02 00:06:25 +01:00
|
|
|
const selected_id = this.data.selected_id();
|
2018-05-04 12:44:28 +02:00
|
|
|
|
|
|
|
if (selected_id !== -1) {
|
|
|
|
this.select_id(selected_id);
|
2013-06-04 22:07:44 +02:00
|
|
|
}
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-05-14 21:18:11 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
update_muting_and_rerender() {
|
2021-01-25 06:23:16 +01:00
|
|
|
if (!this.excludes_muted_topics) {
|
2018-05-04 23:08:57 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-05-04 12:44:28 +02:00
|
|
|
this.data.update_items_for_muting();
|
2013-09-19 00:43:59 +02:00
|
|
|
this.rerender();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-09-19 00:43:59 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
all_messages() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.all_messages();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-14 22:00:32 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
first_unread_message_id() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.first_unread_message_id();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2017-08-02 22:37:13 +02:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
message_range(start, end) {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.message_range(start, end);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2014-01-31 22:06:07 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
get_row(id) {
|
2013-08-16 17:10:22 +02:00
|
|
|
return this.view.get_row(id);
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2013-08-22 19:57:48 +02:00
|
|
|
|
2020-07-23 00:25:12 +02:00
|
|
|
change_message_id(old_id, new_id) {
|
2020-11-12 22:43:04 +01:00
|
|
|
const require_rerender = this.data.change_message_id(old_id, new_id);
|
|
|
|
if (require_rerender) {
|
|
|
|
this.rerender_view();
|
|
|
|
}
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
2016-11-23 05:06:34 +01:00
|
|
|
|
2020-07-20 22:18:43 +02:00
|
|
|
get_last_message_sent_by_me() {
|
2018-05-04 12:44:28 +02:00
|
|
|
return this.data.get_last_message_sent_by_me();
|
2020-07-23 00:25:12 +02:00
|
|
|
}
|
|
|
|
}
|
2013-04-09 19:59:15 +02:00
|
|
|
|
2021-02-28 21:31:33 +01:00
|
|
|
export const all = new MessageList({
|
2021-01-25 06:23:16 +01:00
|
|
|
excludes_muted_topics: false,
|
2018-05-14 15:46:25 +02:00
|
|
|
});
|