compose: Never hide send button.

`Press Enter to send` used to hide `Send` button, we remove that
behaviour.

We show the current state of `Enter` hotkey action via text below
`Send` button which can toggle behaviour on click.
This commit is contained in:
Aman Agrawal
2021-11-25 09:00:04 +00:00
committed by Tim Abbott
parent 219ecea659
commit 25ee6a795e
11 changed files with 78 additions and 70 deletions

View File

@@ -317,12 +317,9 @@ test_ui("enter_with_preview_open", ({override}) => {
// Test sending a message without content. // Test sending a message without content.
$("#compose-textarea").val(""); $("#compose-textarea").val("");
$("#compose .preview_message_area").show(); $("#compose .preview_message_area").show();
$("#enter_sends").prop("checked", true);
user_settings.enter_sends = true; user_settings.enter_sends = true;
compose.enter_with_preview_open(); compose.enter_with_preview_open();
assert.ok($("#enter_sends").prop("checked"));
assert.equal($("#compose-error-msg").html(), "never-been-set"); assert.equal($("#compose-error-msg").html(), "never-been-set");
}); });

View File

@@ -1144,7 +1144,6 @@ test("initialize", ({override, mock_template}) => {
// select_on_focus() // select_on_focus()
override(compose, "toggle_enter_sends_ui", noop);
let channel_patch_called = false; let channel_patch_called = false;
override(channel, "patch", (params) => { override(channel, "patch", (params) => {
assert.equal(params.url, "/json/settings"); assert.equal(params.url, "/json/settings");
@@ -1153,20 +1152,22 @@ test("initialize", ({override, mock_template}) => {
channel_patch_called = true; channel_patch_called = true;
}); });
$("#enter_sends").is = () => false; user_settings.enter_sends = false;
$("#enter_sends").trigger("click"); $(".enter_sends").trigger("click");
assert.equal(user_settings.enter_sends, true);
// Now we re-run both .initialize() and the click handler, this time // Now we re-run both .initialize() and the click handler, this time
// with enter_sends: user_settings.enter_sends being true // with enter_sends: user_settings.enter_sends being true
$("#enter_sends").is = () => true; user_settings.enter_sends = true;
$("#enter_sends").trigger("click"); $(".enter_sends").trigger("click");
assert.equal(user_settings.enter_sends, false);
$("#stream_message_recipient_stream").off("focus"); $("#stream_message_recipient_stream").off("focus");
$("#stream_message_recipient_topic").off("focus"); $("#stream_message_recipient_topic").off("focus");
$("#private_message_recipient").off("focus"); $("#private_message_recipient").off("focus");
$("form#send_message_form").off("keydown"); $("form#send_message_form").off("keydown");
$("form#send_message_form").off("keyup"); $("form#send_message_form").off("keyup");
$("#enter_sends").off("click"); $(".enter_sends").off("click");
$("#private_message_recipient").off("blur"); $("#private_message_recipient").off("blur");
ct.initialize(); ct.initialize();

View File

@@ -28,7 +28,6 @@ const activity = mock_esm("../../static/js/activity");
const alert_words_ui = mock_esm("../../static/js/alert_words_ui"); const alert_words_ui = mock_esm("../../static/js/alert_words_ui");
const attachments_ui = mock_esm("../../static/js/attachments_ui"); const attachments_ui = mock_esm("../../static/js/attachments_ui");
const bot_data = mock_esm("../../static/js/bot_data"); const bot_data = mock_esm("../../static/js/bot_data");
const compose = mock_esm("../../static/js/compose");
const composebox_typeahead = mock_esm("../../static/js/composebox_typeahead"); const composebox_typeahead = mock_esm("../../static/js/composebox_typeahead");
const dark_theme = mock_esm("../../static/js/dark_theme"); const dark_theme = mock_esm("../../static/js/dark_theme");
const emoji_picker = mock_esm("../../static/js/emoji_picker"); const emoji_picker = mock_esm("../../static/js/emoji_picker");
@@ -839,8 +838,6 @@ run_test("user_settings", ({override}) => {
assert_same(user_settings.demote_inactive_streams, 2); assert_same(user_settings.demote_inactive_streams, 2);
} }
override(compose, "toggle_enter_sends_ui", noop);
event = event_fixtures.user_settings__enter_sends; event = event_fixtures.user_settings__enter_sends;
user_settings.enter_sends = false; user_settings.enter_sends = false;
dispatch(event); dispatch(event);

View File

@@ -265,9 +265,10 @@ class CommonUtils {
} }
async ensure_enter_does_not_send(page: Page): Promise<void> { async ensure_enter_does_not_send(page: Page): Promise<void> {
await page.$eval("#enter_sends", (el) => { await page.$eval(".enter_sends_false", (el) => {
if ((el as HTMLInputElement).checked) { if ((el as HTMLElement).style.display !== "none") {
(el as HTMLInputElement).click(); // Click events gets propagated to `.enter_sends` which toggles the value.
(el as HTMLElement).click();
} }
}); });
} }

View File

@@ -119,15 +119,6 @@ export function empty_topic_placeholder() {
return $t({defaultMessage: "(no topic)"}); return $t({defaultMessage: "(no topic)"});
} }
export function toggle_enter_sends_ui() {
const send_button = $("#compose-send-button");
if (user_settings.enter_sends) {
send_button.fadeOut();
} else {
send_button.fadeIn();
}
}
export function create_message_object() { export function create_message_object() {
// Topics are optional, and we provide a placeholder if one isn't given. // Topics are optional, and we provide a placeholder if one isn't given.
let topic = compose_state.topic(); let topic = compose_state.topic();
@@ -413,6 +404,7 @@ export function render_compose_box() {
giphy_enabled: giphy.is_giphy_enabled(), giphy_enabled: giphy.is_giphy_enabled(),
}), }),
); );
$(`.enter_sends_${user_settings.enter_sends}`).show();
} }
export function initialize() { export function initialize() {

View File

@@ -1097,9 +1097,10 @@ export function initialize() {
$("form#send_message_form").on("keydown", handle_keydown); $("form#send_message_form").on("keydown", handle_keydown);
$("form#send_message_form").on("keyup", handle_keyup); $("form#send_message_form").on("keyup", handle_keyup);
$("#enter_sends").on("click", () => { $(".enter_sends").on("click", () => {
user_settings.enter_sends = $("#enter_sends").is(":checked"); user_settings.enter_sends = !user_settings.enter_sends;
compose.toggle_enter_sends_ui(); $(`.enter_sends_${!user_settings.enter_sends}`).hide();
$(`.enter_sends_${user_settings.enter_sends}`).show();
// Refocus in the content box so you can continue typing or // Refocus in the content box so you can continue typing or
// press Enter to send. // press Enter to send.
@@ -1111,10 +1112,6 @@ export function initialize() {
data: {enter_sends: user_settings.enter_sends}, data: {enter_sends: user_settings.enter_sends},
}); });
}); });
$("#enter_sends").prop("checked", user_settings.enter_sends);
if (user_settings.enter_sends) {
$("#compose-send-button").hide();
}
// limit number of items so the list doesn't fall off the screen // limit number of items so the list doesn't fall off the screen
$("#stream_message_recipient_stream").typeahead({ $("#stream_message_recipient_stream").typeahead({

View File

@@ -685,8 +685,8 @@ export function dispatch_normal_event(event) {
} }
if (event.property === "enter_sends") { if (event.property === "enter_sends") {
user_settings.enter_sends = event.value; user_settings.enter_sends = event.value;
$("#enter_sends").prop("checked", user_settings.enter_sends); $(`.enter_sends_${!user_settings.enter_sends}`).hide();
compose.toggle_enter_sends_ui(); $(`.enter_sends_${user_settings.enter_sends}`).show();
break; break;
} }
if (event.property === "presence_enabled") { if (event.property === "presence_enabled") {

View File

@@ -422,6 +422,7 @@ input.recipient_box {
#compose-send-button { #compose-send-button {
height: 25px; height: 25px;
width: 40px;
padding-top: 3px; padding-top: 3px;
padding-bottom: 3px; padding-bottom: 3px;
margin-bottom: 0; margin-bottom: 0;
@@ -429,14 +430,24 @@ input.recipient_box {
font-size: 0.9em; font-size: 0.9em;
} }
#send_controls { .enter_sends {
font-size: 0.8em; font-size: 12px;
height: 2.2em; height: 14px;
padding-left: 4px;
opacity: 0.7;
.compose_checkbox_label { &:hover {
color: hsl(0, 0%, 67%); opacity: 1;
margin: 4px;
} }
.enter_sends_true,
.enter_sends_false {
display: none;
}
}
.compose_left_wrapper {
margin-right: auto;
} }
#stream-message, #stream-message,
@@ -479,9 +490,11 @@ input.recipient_box {
.compose_right_float_container { .compose_right_float_container {
display: flex; display: flex;
flex-direction: column;
align-items: flex-end;
white-space: nowrap; white-space: nowrap;
gap: 4px; gap: 4px;
margin-top: 10px; margin-top: 2px;
} }
a.compose_control_button { a.compose_control_button {
@@ -515,12 +528,6 @@ a.compose_control_button.hide {
cursor: ns-resize; cursor: ns-resize;
} }
#enter_sends {
vertical-align: middle;
margin-top: -2px;
margin-right: 4px;
}
.inline-subscribe-error { .inline-subscribe-error {
margin-left: 5px; margin-left: 5px;
} }

View File

@@ -95,16 +95,27 @@
<div id="below-compose-content"> <div id="below-compose-content">
<div class="compose_right_float_container order-3"> <div class="compose_right_float_container order-3">
<button type="submit" id="compose-send-button" class="button small send_message animated-purple-button" title="{{t 'Send' }} (Ctrl + Enter)">{{t 'Send' }}</button> <button type="submit" id="compose-send-button" class="button small send_message animated-purple-button" title="{{t 'Send' }} (Ctrl + Enter)">{{t 'Send' }}</button>
<div class="enter_sends order-2">
<label id="enter-sends-label" class="compose_checkbox_label tippy-zulip-tooltip" data-tippy-content="Click to switch">
<span class="enter_sends_true">
{{t 'Enter to send' }}
</span>
<span class="enter_sends_false">
{{t 'Ctrl + Enter to send' }}
</span>
<i class="fa fa-exchange" aria-hidden="true"></i>
<span class="enter_sends_true">
{{t "Ctrl + Enter to add a new line" }}
</span>
<span class="enter_sends_false">
{{t "Enter to add a new line" }}
</span>
</label>
</div>
</div> </div>
{{> compose_control_buttons }} {{> compose_control_buttons }}
<div class="compose_right_float_container order-2"> <div class="compose_right_float_container order-2">
<span id="compose_limit_indicator"></span> <span id="compose_limit_indicator"></span>
<div id="send_controls" class="new-style">
<label id="enter-sends-label" class="compose_checkbox_label checkbox">
<input type="checkbox" tabindex="0" id="enter_sends" />
<span></span>{{t 'Press Enter to send' }}
</label>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,19 +1,21 @@
<div class="compose_control_buttons_container order-1"> <div class="compose_left_wrapper order-1">
<input type="file" class="file_input notvisible pull-left" multiple /> <div class="compose_control_buttons_container order-1">
{{#if file_upload_enabled }} <input type="file" class="file_input notvisible pull-left" multiple />
<a role="button" class="compose_control_button compose_upload_file fa fa-paperclip notdisplayed" aria-label="{{t 'Upload files' }}" tabindex=0 data-tippy-content="{{t 'Upload files' }}"></a> {{#if file_upload_enabled }}
{{/if}} <a role="button" class="compose_control_button compose_upload_file fa fa-paperclip notdisplayed" aria-label="{{t 'Upload files' }}" tabindex=0 data-tippy-content="{{t 'Upload files' }}"></a>
<a role="button" class="markdown_preview compose_control_button fa fa-eye" aria-label="{{t 'Preview' }}" tabindex=0 data-tippy-content="{{t 'Preview' }}"></a> {{/if}}
<a role="button" class="undo_markdown_preview compose_control_button fa fa-edit" aria-label="{{t 'Write' }}" tabindex=0 style="display:none;" data-tippy-content="{{t 'Write' }}"></a> <a role="button" class="markdown_preview compose_control_button fa fa-eye" aria-label="{{t 'Preview' }}" tabindex=0 data-tippy-content="{{t 'Preview' }}"></a>
<a role="button" class="compose_control_button fa fa-video-camera video_link" aria-label="{{t 'Add video call' }}" tabindex=0 data-tippy-content="{{t 'Add video call' }}"></a> <a role="button" class="undo_markdown_preview compose_control_button fa fa-edit" aria-label="{{t 'Write' }}" tabindex=0 style="display:none;" data-tippy-content="{{t 'Write' }}"></a>
<a role="button" class="compose_control_button fa fa-smile-o emoji_map" aria-label="{{t 'Add emoji' }}" tabindex=0 data-tippy-content="{{t 'Add emoji' }}"></a> <a role="button" class="compose_control_button fa fa-video-camera video_link" aria-label="{{t 'Add video call' }}" tabindex=0 data-tippy-content="{{t 'Add video call' }}"></a>
<a role="button" class="compose_control_button compose_gif_icon {{#unless giphy_enabled }} hide {{/unless}} zulip-icon zulip-icon-gif" aria-label="{{t 'Add GIF' }}" tabindex=0 data-tippy-content="{{t 'Add GIF' }}"></a> <a role="button" class="compose_control_button fa fa-smile-o emoji_map" aria-label="{{t 'Add emoji' }}" tabindex=0 data-tippy-content="{{t 'Add emoji' }}"></a>
<a role="button" class="compose_control_button fa fa-clock-o time_pick" aria-label="{{t 'Add global time' }}" tabindex=0 data-tippy-content="{{t 'Add global time<br />Everyone sees global times in their own time zone.' }}" data-tippy-maxWidth="none" data-tippy-allowHtml="true"></a> <a role="button" class="compose_control_button compose_gif_icon {{#unless giphy_enabled }} hide {{/unless}} zulip-icon zulip-icon-gif" aria-label="{{t 'Add GIF' }}" tabindex=0 data-tippy-content="{{t 'Add GIF' }}"></a>
<div class="divider">|</div> <a role="button" class="compose_control_button fa fa-clock-o time_pick" aria-label="{{t 'Add global time' }}" tabindex=0 data-tippy-content="{{t 'Add global time<br />Everyone sees global times in their own time zone.' }}" data-tippy-maxWidth="none" data-tippy-allowHtml="true"></a>
<a role="button" data-format-type="bold" class="compose_control_button fa fa-bold formatting_button" aria-label="{{t 'Bold' }}" tabindex=0 data-tippy-content="{{t 'Bold' }}"></a> <div class="divider">|</div>
<a role="button" data-format-type="italic" class="compose_control_button fa fa-italic formatting_button" aria-label="{{t 'Italic' }}" tabindex=0 data-tippy-content="{{t 'Italic' }}"></a> <a role="button" data-format-type="bold" class="compose_control_button fa fa-bold formatting_button" aria-label="{{t 'Bold' }}" tabindex=0 data-tippy-content="{{t 'Bold' }}"></a>
<a role="button" data-format-type="link" class="compose_control_button fa fa-link formatting_button" aria-label="{{t 'Link' }}" tabindex=0 data-tippy-content="{{t 'Link' }}"></a> <a role="button" data-format-type="italic" class="compose_control_button fa fa-italic formatting_button" aria-label="{{t 'Italic' }}" tabindex=0 data-tippy-content="{{t 'Italic' }}"></a>
<div class="divider">|</div> <a role="button" data-format-type="link" class="compose_control_button fa fa-link formatting_button" aria-label="{{t 'Link' }}" tabindex=0 data-tippy-content="{{t 'Link' }}"></a>
<a role="button" class="message-control-link" tabindex=0 data-overlay-trigger="message-formatting">{{t 'Help' }}</a> <div class="divider">|</div>
<span id="sending-indicator"></span> <a role="button" class="message-control-link" tabindex=0 data-overlay-trigger="message-formatting">{{t 'Help' }}</a>
<span id="sending-indicator"></span>
</div>
</div> </div>

View File

@@ -168,6 +168,9 @@ IGNORED_PHRASES = [
r"University of California San Diego", r"University of California San Diego",
# Used in stream creation form # Used in stream creation form
r"email hidden", r"email hidden",
# Use in compose box.
r"to send",
r"to add a new line",
] ]
# Sort regexes in descending order of their lengths. As a result, the # Sort regexes in descending order of their lengths. As a result, the