recent_topics: Display compose box & enable compose hotkeys.

We move compose from being a part of message feed to
being a part of  middle column which is a common parent of recent
topics and message feed. This allows us to use a common compose
box for both the views. Fortunately, compose actions were
independent of this change so there weren't any evident
side effects.

Fixes #17543
This commit is contained in:
Aman Agrawal
2021-03-18 12:57:28 +00:00
committed by Tim Abbott
parent 1bc21a6a2f
commit 51acbefc8a
11 changed files with 111 additions and 62 deletions

View File

@@ -30,6 +30,10 @@ mock_esm("../../static/js/notifications", {
mock_esm("../../static/js/reload_state", {
is_in_progress: () => false,
});
mock_esm("../../static/js/recent_topics", {
is_visible: noop,
set_compose_defaults: noop,
});
mock_esm("../../static/js/drafts", {
update_draft: noop,
});

View File

@@ -86,3 +86,11 @@ run_test("reply_label", () => {
test_reply_label(expected_label);
}
});
run_test("test_custom_message_input", () => {
compose_closed_ui.update_reply_recipient_label({
stream: "stream test",
topic: "topic test",
});
test_reply_label("#stream test > topic test");
});

View File

@@ -65,11 +65,8 @@ const ListWidget = mock_esm("../../static/js/list_widget", {
render_item: (item) => ListWidget.modifier(item),
});
mock_esm("../../static/js/compose_actions", {
cancel: noop,
});
mock_esm("../../static/js/drafts", {
update_draft: noop,
mock_esm("../../static/js/compose", {
update_closed_compose_buttons_for_recent_topics: noop,
});
mock_esm("../../static/js/hash_util", {
by_stream_uri: () => "https://www.example.com",

View File

@@ -200,6 +200,11 @@ export function update_closed_compose_buttons_for_stream() {
update_closed_compose_buttons(text_stream);
}
export function update_closed_compose_buttons_for_recent_topics() {
const text_stream = $t({defaultMessage: "Compose message"});
update_closed_compose_buttons(text_stream);
}
function update_fade() {
if (!compose_state.composing()) {
return;

View File

@@ -19,10 +19,10 @@ import * as narrow_state from "./narrow_state";
import * as notifications from "./notifications";
import {page_params} from "./page_params";
import * as people from "./people";
import * as recent_topics from "./recent_topics";
import * as reload_state from "./reload_state";
import * as stream_bar from "./stream_bar";
import * as stream_data from "./stream_data";
import * as ui_util from "./ui_util";
import * as unread_ops from "./unread_ops";
export function blur_compose_inputs() {
@@ -132,7 +132,6 @@ export function complete_starting_tasks(msg_type, opts) {
// makes testing a bit easier.
maybe_scroll_up_selected_message();
ui_util.change_tab_to("#message_feed_container");
compose_fade.start_compose(msg_type);
stream_bar.decorate(opts.stream, $("#stream-message .message_header_stream"), true);
$(document).trigger(new $.Event("compose_started.zulip", opts));
@@ -215,6 +214,7 @@ export function start(msg_type, opts) {
expand_compose_box();
opts = fill_in_opts_from_current_narrowed_view(msg_type, opts);
// If we are invoked by a compose hotkey (c or x) or new topic
// button, do not assume that we know what the message's topic or
// PM recipient should be.
@@ -290,47 +290,55 @@ export function cancel() {
}
export function respond_to_message(opts) {
let msg_type;
// Before initiating a reply to a message, if there's an
// in-progress composition, snapshot it.
drafts.update_draft();
const message = message_lists.current.selected_message();
if (message === undefined) {
// empty narrow implementation
if (
!narrow_state.narrowed_by_pm_reply() &&
!narrow_state.narrowed_by_stream_reply() &&
!narrow_state.narrowed_by_topic_reply()
) {
compose.nonexistent_stream_reply_error();
let message;
let msg_type;
if (recent_topics.is_visible()) {
message = recent_topics.get_focused_row_message();
if (message === undefined) {
return;
}
const current_filter = narrow_state.filter();
const first_term = current_filter.operators()[0];
const first_operator = first_term.operator;
const first_operand = first_term.operand;
} else {
message = message_lists.current.selected_message();
if (first_operator === "stream" && !stream_data.is_subscribed(first_operand)) {
compose.nonexistent_stream_reply_error();
if (message === undefined) {
// empty narrow implementation
if (
!narrow_state.narrowed_by_pm_reply() &&
!narrow_state.narrowed_by_stream_reply() &&
!narrow_state.narrowed_by_topic_reply()
) {
compose.nonexistent_stream_reply_error();
return;
}
const current_filter = narrow_state.filter();
const first_term = current_filter.operators()[0];
const first_operator = first_term.operator;
const first_operand = first_term.operand;
if (first_operator === "stream" && !stream_data.is_subscribed(first_operand)) {
compose.nonexistent_stream_reply_error();
return;
}
// Set msg_type to stream by default in the case of an empty
// home view.
msg_type = "stream";
if (narrow_state.narrowed_by_pm_reply()) {
msg_type = "private";
}
const new_opts = fill_in_opts_from_current_narrowed_view(msg_type, opts);
start(new_opts.message_type, new_opts);
return;
}
// Set msg_type to stream by default in the case of an empty
// home view.
msg_type = "stream";
if (narrow_state.narrowed_by_pm_reply()) {
msg_type = "private";
if (message_lists.current.can_mark_messages_read()) {
unread_ops.notify_server_message_read(message);
}
const new_opts = fill_in_opts_from_current_narrowed_view(msg_type, opts);
start(new_opts.message_type, new_opts);
return;
}
if (message_lists.current.can_mark_messages_read()) {
unread_ops.notify_server_message_read(message);
}
// Important note: A reply_type of 'personal' is for the R hotkey

View File

@@ -4,8 +4,8 @@ import * as compose_actions from "./compose_actions";
import * as message_lists from "./message_lists";
import * as popovers from "./popovers";
function update_reply_recipient_label() {
const message = message_lists.current.selected_message();
export function update_reply_recipient_label(message) {
message = message || message_lists.current.selected_message();
let recipient_label = "";
if (message) {
if (message.stream && message.topic) {

View File

@@ -778,15 +778,13 @@ export function process_hotkey(e, hotkey) {
return true;
}
// We don't want hotkeys below this to work when recent topics is
// open. These involve compose box hotkeys and hotkeys that can only
// be done performed on a message.
if (recent_topics.is_visible()) {
return false;
}
// Shortcuts that are useful with an empty message feed, like opening compose.
switch (event_name) {
case "reply_message": // 'r': respond to message
// Note that you can "Enter" to respond to messages as well,
// but that is handled in process_enter_key().
compose_actions.respond_to_message({trigger: "hotkey"});
return true;
case "compose": // 'c': compose
compose_actions.start("stream", {trigger: "compose_hotkey"});
return true;
@@ -796,11 +794,6 @@ export function process_hotkey(e, hotkey) {
case "open_drafts":
drafts.launch();
return true;
case "reply_message": // 'r': respond to message
// Note that you can "Enter" to respond to messages as well,
// but that is handled in process_enter_key().
compose_actions.respond_to_message({trigger: "hotkey"});
return true;
case "C_deprecated":
ui.maybe_show_deprecation_notice("C");
return true;
@@ -809,6 +802,12 @@ export function process_hotkey(e, hotkey) {
return true;
}
// We don't want hotkeys below this to work when recent topics is
// open. These involve hotkeys that can only be performed on a message.
if (recent_topics.is_visible()) {
return false;
}
if (message_lists.current.empty()) {
return false;
}

View File

@@ -4,8 +4,9 @@ import render_recent_topic_row from "../templates/recent_topic_row.hbs";
import render_recent_topics_filters from "../templates/recent_topics_filters.hbs";
import render_recent_topics_body from "../templates/recent_topics_table.hbs";
import * as compose_actions from "./compose_actions";
import * as drafts from "./drafts";
import * as compose from "./compose";
import * as compose_closed_ui from "./compose_closed_ui";
import * as compose_state from "./compose_state";
import * as hash_util from "./hash_util";
import * as hashchange from "./hashchange";
import * as ListWidget from "./list_widget";
@@ -75,6 +76,7 @@ export function is_in_focus() {
// recent topics.
return (
hashchange.in_recent_topics_hash() &&
!compose_state.composing() &&
!popovers.any_active() &&
!overlays.is_active() &&
!$(".home-page-input").is(":focus")
@@ -120,9 +122,28 @@ function set_table_focus(row, col) {
topic_rows.eq(row).find(".recent_topics_focusable").eq(col).children().trigger("focus");
}, 0);
current_focus_elem = "table";
const topic_row = topic_rows.eq(row);
const message = {
stream: topic_row.find(".recent_topic_stream a").text(),
topic: topic_row.find(".recent_topic_name a").text(),
};
compose_closed_ui.update_reply_recipient_label(message);
return true;
}
export function get_focused_row_message() {
if (is_table_focused()) {
const recent_topic_id_prefix_len = "recent_topic:".length;
const topic_rows = $("#recent_topics_table table tbody tr");
const topic_row = topic_rows.eq(row_focus);
const topic_id = topic_row.attr("id").slice(recent_topic_id_prefix_len);
const topic_last_msg_id = topics.get(topic_id).last_msg_id;
return message_store.get(topic_last_msg_id);
}
return undefined;
}
function revive_current_focus() {
// After re-render, the current_focus_elem is no longer linked
// to the focused element, this function attempts to revive the
@@ -538,13 +559,10 @@ export function show() {
$("#message_view_header_underpadding").hide();
$(".header").css("padding-bottom", "0px");
// Save text in compose box if open.
drafts.update_draft();
// Close the compose box, this removes
// any arbitrary bug for compose box in recent topics.
// This is required since, Recent Topics is the only view
// with no compose box.
compose_actions.cancel();
// We want to show `new stream message` instead of
// `new topic`, which we are already doing in this
// function. So, we reuse it here.
compose.update_closed_compose_buttons_for_recent_topics();
narrow_state.reset_current_filter();
narrow.set_narrow_title("Recent topics");

View File

@@ -72,6 +72,17 @@
.table_fix_head table {
/* To keep border properties to the thead th. */
border-collapse: separate;
/* For visual reasons, in a message feed, we require a large
* bottom_whitespace to make it convenient to display new
* messages as they come in and prevent occluding the last
* message with an open compose box. Here, the bottom item
* is rarely interesting context for a message one is
* composing, but we do need at least 41px to allow the
* close-compose-box UI element (including border) to not
* overlap content. Add some more margin so that user
* can clearly see the end of the topics.
*/
margin-bottom: 100px;
}
#recent_topics_filter_buttons {

View File

@@ -156,8 +156,6 @@
{% include "zerver/app/message_history.html" %}
{% include "zerver/app/delete_message.html" %}
<div id="compose" {% if embedded %}data-embedded{% endif %}>
</div>
<audio id="notification-sound-audio">
<source id="notification-sound-source-ogg" type="audio/ogg" />
<source id="notification-sound-source-mp3" type="audio/mpeg" />

View File

@@ -123,6 +123,7 @@
</div>
{% include "zerver/app/home.html" %}
</div>
<div id="compose" {% if embedded %}data-embedded{% endif %}></div>
</div><!--/tab-content-->
</div>
<div class="column-right">