message_list_view: Create group and message container all at once.

To be able to convert this module to typescript, we can't create
these objects iteratively, we have to collect the property values
and create it all at once. Partially formed objects aren't very
easy to type.
This commit is contained in:
evykassirer 2024-09-09 13:45:03 -07:00 committed by Tim Abbott
parent e65bf5cbe2
commit bf64ac7918
1 changed files with 158 additions and 116 deletions

View File

@ -284,54 +284,85 @@ function maybe_restore_focus_to_message_edit_form() {
}, 0);
}
function populate_group_from_message_container(group, message_container) {
group.is_stream = message_container.msg.is_stream;
group.is_private = message_container.msg.is_private;
function populate_group_from_message(message, date_unchanged, subscription_markers) {
const is_stream = message.is_stream;
const is_private = message.is_private;
const display_recipient = message.display_recipient;
const message_group_id = _.uniqueId("message_group_");
const date = get_group_display_date(message);
if (group.is_stream) {
const color = stream_data.get_color(message_container.msg.stream_id);
group.recipient_bar_color = stream_color.get_recipient_bar_color(color);
group.stream_privacy_icon_color = stream_color.get_stream_privacy_icon_color(color);
group.invite_only = stream_data.is_invite_only_by_stream_id(
message_container.msg.stream_id,
);
group.is_web_public = stream_data.is_web_public(message_container.msg.stream_id);
group.topic = message_container.msg.topic;
group.match_topic = util.get_match_topic(message_container.msg);
group.stream_url = message_container.stream_url;
group.topic_url = message_container.topic_url;
const sub = sub_store.get(message_container.msg.stream_id);
if (is_stream) {
const color = stream_data.get_color(message.stream_id);
const recipient_bar_color = stream_color.get_recipient_bar_color(color);
const stream_privacy_icon_color = stream_color.get_stream_privacy_icon_color(color);
const invite_only = stream_data.is_invite_only_by_stream_id(message.stream_id);
const is_web_public = stream_data.is_web_public(message.stream_id);
const topic = message.topic;
const match_topic = util.get_match_topic(message);
const stream_url = hash_util.by_stream_url(message.stream_id);
const topic_url = hash_util.by_stream_topic_url(message.stream_id, message.topic);
const sub = sub_store.get(message.stream_id);
let stream_id;
if (sub === undefined) {
// Hack to handle unusual cases like the tutorial where
// the streams used don't actually exist in the subs
// module. Ideally, we'd clean this up by making the
// tutorial populate stream_settings_ui.js "properly".
group.stream_id = -1;
stream_id = -1;
} else {
group.stream_id = sub.stream_id;
stream_id = sub.stream_id;
}
group.is_subscribed = stream_data.is_subscribed(group.stream_id);
group.topic_is_resolved = resolved_topic.is_resolved(group.topic);
group.visibility_policy = user_topics.get_topic_visibility_policy(
group.stream_id,
group.topic,
);
const is_subscribed = stream_data.is_subscribed(stream_id);
const topic_is_resolved = resolved_topic.is_resolved(topic);
const visibility_policy = user_topics.get_topic_visibility_policy(stream_id, topic);
// The following field is not specific to this group, but this is the
// easiest way we've figured out for passing the data to the template rendering.
group.all_visibility_policies = user_topics.all_visibility_policies;
} else if (group.is_private) {
group.pm_with_url = message_container.pm_with_url;
group.recipient_users = get_users_for_recipient_row(message_container.msg);
group.display_reply_to_for_tooltip = message_store.get_pm_full_names(
people.pm_with_user_ids(message_container.msg),
);
}
group.display_recipient = message_container.msg.display_recipient;
group.topic_links = message_container.msg.topic_links;
const all_visibility_policies = user_topics.all_visibility_policies;
Object.assign(group, get_topic_edit_properties(message_container.msg));
group.date = get_group_display_date(message_container.msg);
const topic_links = message.topic_links;
return {
message_group_id,
message_containers: [],
is_stream,
...get_topic_edit_properties(message),
...subscription_markers,
date,
display_recipient,
date_unchanged,
topic_links,
topic,
recipient_bar_color,
stream_privacy_icon_color,
invite_only,
is_web_public,
match_topic,
stream_url,
topic_url,
stream_id,
is_subscribed,
topic_is_resolved,
visibility_policy,
all_visibility_policies,
};
}
// Private message group
const user_ids = people.pm_with_user_ids(message);
return {
message_group_id,
message_containers: [],
is_stream,
is_private,
...get_topic_edit_properties(message),
date,
date_unchanged,
display_recipient,
pm_with_url: message.pm_with_url,
recipient_users: get_users_for_recipient_row(message),
display_reply_to_for_tooltip: message_store.get_pm_full_names(user_ids),
};
}
// MessageListView is the module responsible for rendering a
@ -619,101 +650,114 @@ export class MessageListView {
return undefined;
}
build_message_groups(message_containers) {
const start_group = (prev_message, message_for_next_group) => {
const group = {
message_containers: [],
message_group_id: _.uniqueId("message_group_"),
};
update_group_date(group, message_for_next_group, prev_message);
this.maybe_add_subscription_marker_to_group(
group,
prev_message,
message_for_next_group,
);
return group;
};
let current_group = start_group();
build_message_groups(messages) {
const new_message_groups = [];
let prev;
let current_group;
let current_group_message_containers = [];
let prev_message_container;
const add_message_container_to_group = (message_container) => {
current_group.message_containers.push(message_container);
current_group_message_containers.push(message_container);
};
const start_group = (prev_message, message_for_next_group) => {
current_group = populate_group_from_message(
message_for_next_group,
same_day(message_for_next_group, prev_message),
this.get_possible_group_subscription_markers(prev_message, message_for_next_group),
);
};
const finish_group = () => {
if (current_group.message_containers.length > 0) {
populate_group_from_message_container(
current_group,
current_group.message_containers[0],
);
if (current_group_message_containers.length > 0) {
current_group.message_containers = current_group_message_containers;
new_message_groups.push(current_group);
}
current_group_message_containers = [];
};
for (const message_container of message_containers) {
const message_reactions = reactions.get_message_reactions(message_container.msg);
message_container.msg.message_reactions = message_reactions;
message_container.include_recipient = false;
for (const message of messages) {
const message_reactions = reactions.get_message_reactions(message);
message.message_reactions = message_reactions;
// These will be used to build the message container
let include_recipient = false;
let subscribed;
let unsubscribed;
let stream_url;
let topic_url;
let pm_with_url;
let include_sender;
let want_date_divider;
let date_divider_html;
if (
same_recipient(prev, message_container) &&
prev_message_container &&
util.same_recipient(prev_message_container.msg, message) &&
this.collapse_messages &&
prev.msg.historical === message_container.msg.historical
prev_message_container.msg.historical === message.historical
) {
add_message_container_to_group(message_container);
const date_divider_data = get_message_date_divider_data({
prev_message: prev.msg,
curr_message: message_container.msg,
prev_message: prev_message_container.msg,
curr_message: message,
});
message_container.want_date_divider = date_divider_data.want_date_divider;
message_container.date_divider_html = date_divider_data.date_divider_html;
want_date_divider = date_divider_data.want_date_divider;
date_divider_html = date_divider_data.date_divider_html;
} else {
finish_group();
current_group = start_group(prev?.msg, message_container.msg);
add_message_container_to_group(message_container);
start_group(prev_message_container?.msg, message);
want_date_divider = false;
date_divider_html = undefined;
include_recipient = true;
subscribed = false;
unsubscribed = false;
message_container.want_date_divider = false;
message_container.date_divider_html = undefined;
message_container.include_recipient = true;
message_container.subscribed = false;
message_container.unsubscribed = false;
if (message_container.msg.type === "stream") {
message_container.stream_url = hash_util.by_stream_url(
message_container.msg.stream_id,
);
message_container.topic_url = hash_util.by_stream_topic_url(
message_container.msg.stream_id,
message_container.msg.topic,
);
if (message.type === "stream") {
stream_url = hash_util.by_stream_url(message.stream_id);
topic_url = hash_util.by_stream_topic_url(message.stream_id, message.topic);
} else {
message_container.pm_with_url = message_container.msg.pm_with_url;
pm_with_url = message.pm_with_url;
}
}
message_container.include_sender = true;
include_sender = true;
if (
!message_container.include_recipient &&
!prev.status_message &&
same_day(prev?.msg, message_container?.msg) &&
same_sender(prev, message_container)
!include_recipient &&
prev_message_container &&
!prev_message_container.status_message &&
same_day(prev_message_container.msg, message) &&
prev_message_container.msg.sender_id === message.sender_id
) {
message_container.include_sender = false;
include_sender = false;
}
Object.assign(
message_container,
this.get_calculated_message_container_variables(
message_container.msg,
message_container.include_sender,
),
const calculated_variables = this.get_calculated_message_container_variables(
message,
include_sender,
);
const message_container = {
msg: message,
include_recipient,
...(subscribed && {subscribed}),
...(unsubscribed && {unsubscribed}),
...(stream_url && {stream_url}),
...(topic_url && {topic_url}),
...(pm_with_url && {pm_with_url}),
want_date_divider,
date_divider_html,
mention_classname: null,
...calculated_variables,
...this.get_edited_notice_locations(
include_sender,
calculated_variables.is_hidden,
Boolean(calculated_variables.status_message),
),
};
add_message_container_to_group(message_container);
prev = message_container;
prev_message_container = message_container;
}
finish_group();
@ -986,15 +1030,9 @@ export class MessageListView {
// than auto-scrolling.
const started_scrolled_up = message_viewport.is_scrolled_up();
// The messages we are being asked to render are shared with between
// all messages lists. To prevent having both list views overwriting
// each other's data we will make a new message object to add data to
// for rendering.
const message_containers = messages.map((message) => {
for (const message of messages) {
message.url = hash_util.by_conversation_and_time_url(message);
return {msg: message};
});
}
const save_scroll_position = () => {
if (orig_scrolltop_offset === undefined && this.selected_row().length > 0) {
@ -1013,11 +1051,8 @@ export class MessageListView {
}
};
if (message_containers.length === 0) {
return undefined;
}
const new_message_groups = this.build_message_groups(message_containers);
const new_message_groups = this.build_message_groups(messages);
const message_containers = new_message_groups.flatMap((group) => group.message_containers);
const message_actions = this.merge_message_groups(new_message_groups, where);
const new_dom_elements = [];
let $rendered_groups;
@ -1484,7 +1519,14 @@ export class MessageListView {
// call; it was introduced in an earlier version of this code
// where we constructed an artificial message group for this
// rerendering rather than looking up the original version.
populate_group_from_message_container(group, group.message_containers[0]);
Object.assign(
group,
populate_group_from_message(
group.message_containers[0].msg,
group.date_unchanged,
undefined,
),
);
const $rendered_recipient_row = $(render_recipient_row(group));