mirror of
https://github.com/zulip/zulip.git
synced 2025-11-10 00:46:03 +00:00
compose: Disable send button when upload/s are in progress.
Earlier, the send button's state was determined independently by the message length and the upload status, and its containing `div`'s state was separately determined on recipient change by whether the user had permission to post in that stream, or if direct messages were allowed in the organisation. The main problem was that as the message length check was run on each character input, it often overrode the upload status check. Now for consistency, the code has been refactored to always disable the send button by accordingly styling its containing `div`; and using the observer pattern we update it anytime the message length, upload status, or the recipient changes, considering **all** of them together. (The Save button when editing a message still works like before -- only dependent on upload status.) Fixes: #21135.
This commit is contained in:
@@ -120,7 +120,7 @@ export function get_posting_policy_error_message() {
|
||||
export function check_posting_policy_for_compose_box() {
|
||||
const banner_text = get_posting_policy_error_message();
|
||||
if (banner_text === "") {
|
||||
$(".message-send-controls").removeClass("disabled-message-send-controls");
|
||||
compose_validate.set_recipient_disallowed(false);
|
||||
compose_banner.clear_errors();
|
||||
return;
|
||||
}
|
||||
@@ -129,7 +129,7 @@ export function check_posting_policy_for_compose_box() {
|
||||
if (compose_state.selected_recipient_id === "direct") {
|
||||
banner_classname = compose_banner.CLASSNAMES.private_messages_disabled;
|
||||
}
|
||||
$(".message-send-controls").addClass("disabled-message-send-controls");
|
||||
compose_validate.set_recipient_disallowed(true);
|
||||
compose_banner.show_error_message(banner_text, banner_classname, $("#compose_banners"));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import render_narrow_to_compose_recipients_tooltip from "../templates/narrow_to_
|
||||
|
||||
import * as compose_recipient from "./compose_recipient";
|
||||
import * as compose_state from "./compose_state";
|
||||
import * as compose_validate from "./compose_validate";
|
||||
import {$t} from "./i18n";
|
||||
import * as narrow_state from "./narrow_state";
|
||||
import * as popover_menus from "./popover_menus";
|
||||
@@ -133,7 +134,9 @@ export function initialize() {
|
||||
// in the new design
|
||||
target: [".disabled-message-send-controls"],
|
||||
maxWidth: 350,
|
||||
content: () => compose_recipient.get_posting_policy_error_message(),
|
||||
content: () =>
|
||||
compose_recipient.get_posting_policy_error_message() ||
|
||||
compose_validate.get_disabled_send_tooltip(),
|
||||
appendTo: () => document.body,
|
||||
onHidden(instance) {
|
||||
instance.destroy();
|
||||
|
||||
@@ -23,9 +23,43 @@ import * as sub_store from "./sub_store";
|
||||
import * as util from "./util";
|
||||
|
||||
let user_acknowledged_wildcard = false;
|
||||
let upload_in_progress = false;
|
||||
let message_too_long = false;
|
||||
let recipient_disallowed = false;
|
||||
|
||||
export let wildcard_mention_large_stream_threshold = 15;
|
||||
|
||||
export function set_upload_in_progress(status) {
|
||||
upload_in_progress = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
function set_message_too_long(status) {
|
||||
message_too_long = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
export function set_recipient_disallowed(status) {
|
||||
recipient_disallowed = status;
|
||||
update_send_button_status();
|
||||
}
|
||||
|
||||
function update_send_button_status() {
|
||||
$(".message-send-controls").toggleClass(
|
||||
"disabled-message-send-controls",
|
||||
message_too_long || upload_in_progress || recipient_disallowed,
|
||||
);
|
||||
}
|
||||
|
||||
export function get_disabled_send_tooltip() {
|
||||
if (message_too_long) {
|
||||
return $t({defaultMessage: "Message length shouldn't be greater than 10000 characters."});
|
||||
} else if (upload_in_progress) {
|
||||
return $t({defaultMessage: "Cannot send message while files are being uploaded."});
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export function needs_subscribe_warning(user_id, stream_id) {
|
||||
// This returns true if all of these conditions are met:
|
||||
// * the user is valid
|
||||
@@ -655,7 +689,7 @@ export function check_overflow_text() {
|
||||
compose_banner.CLASSNAMES.message_too_long,
|
||||
$("#compose_banners"),
|
||||
);
|
||||
$("#compose-send-button").prop("disabled", true);
|
||||
set_message_too_long(true);
|
||||
} else if (text.length > 0.9 * max_length) {
|
||||
$indicator.removeClass("over_limit");
|
||||
$("textarea#compose-textarea").removeClass("over_limit");
|
||||
@@ -665,13 +699,13 @@ export function check_overflow_text() {
|
||||
max_length,
|
||||
}),
|
||||
);
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
set_message_too_long(false);
|
||||
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.message_too_long)}`).remove();
|
||||
} else {
|
||||
$indicator.text("");
|
||||
$("textarea#compose-textarea").removeClass("over_limit");
|
||||
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
set_message_too_long(false);
|
||||
$(`#compose_banners .${CSS.escape(compose_banner.CLASSNAMES.message_too_long)}`).remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as compose_banner from "./compose_banner";
|
||||
import * as compose_reply from "./compose_reply";
|
||||
import * as compose_state from "./compose_state";
|
||||
import * as compose_ui from "./compose_ui";
|
||||
import * as compose_validate from "./compose_validate";
|
||||
import {csrf_token} from "./csrf";
|
||||
import {$t} from "./i18n";
|
||||
import * as message_lists from "./message_lists";
|
||||
@@ -129,7 +130,11 @@ export function get_item(key, config, file_id) {
|
||||
export function hide_upload_banner(uppy, config, file_id) {
|
||||
get_item("upload_banner", config, file_id).remove();
|
||||
if (uppy.getFiles().length === 0) {
|
||||
get_item("send_button", config).prop("disabled", false);
|
||||
if (config.mode === "compose") {
|
||||
compose_validate.set_upload_in_progress(false);
|
||||
} else {
|
||||
get_item("send_button", config).prop("disabled", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +162,6 @@ export function show_error_message(
|
||||
message = $t({defaultMessage: "An unknown error occurred."}),
|
||||
file_id = null,
|
||||
) {
|
||||
get_item("send_button", config).prop("disabled", false);
|
||||
if (file_id) {
|
||||
$(`${get_item("upload_banner_identifier", config, file_id)} .moving_bar`).hide();
|
||||
get_item("upload_banner", config, file_id).removeClass("info").addClass("error");
|
||||
@@ -195,8 +199,6 @@ export async function upload_files(uppy, config, files) {
|
||||
get_item("markdown_preview_hide_button", config).trigger("click");
|
||||
}
|
||||
|
||||
get_item("send_button", config).prop("disabled", true);
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
compose_ui.insert_syntax_and_focus(
|
||||
@@ -217,6 +219,11 @@ export async function upload_files(uppy, config, files) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (config.mode === "compose") {
|
||||
compose_validate.set_upload_in_progress(true);
|
||||
} else {
|
||||
get_item("send_button", config).prop("disabled", true);
|
||||
}
|
||||
add_upload_banner(
|
||||
config,
|
||||
"info",
|
||||
@@ -405,16 +412,16 @@ export function setup_upload(config) {
|
||||
});
|
||||
|
||||
uppy.on("upload-error", (file, _error, response) => {
|
||||
// The files with failed upload should be removed since uppy doesn't allow files in the store
|
||||
// to be re-uploaded again.
|
||||
uppy.removeFile(file.id);
|
||||
|
||||
const message = response ? response.body.msg : undefined;
|
||||
// Hide the upload status banner on error so only the error banner shows
|
||||
hide_upload_banner(uppy, config, file.id);
|
||||
show_error_message(config, message, file.id);
|
||||
compose_ui.replace_syntax(get_translated_status(file), "", get_item("textarea", config));
|
||||
compose_ui.autosize_textarea(get_item("textarea", config));
|
||||
|
||||
// The files with failed upload should be removed since uppy doesn't allow files in the store
|
||||
// to be re-uploaded again.
|
||||
uppy.removeFile(file.id);
|
||||
});
|
||||
|
||||
uppy.on("restriction-failed", (file) => {
|
||||
|
||||
@@ -561,7 +561,6 @@ test_ui("test_check_overflow_text", ({mock_template}) => {
|
||||
|
||||
const $textarea = $("textarea#compose-textarea");
|
||||
const $indicator = $("#compose-limit-indicator");
|
||||
const $send_button = $("#compose-send-button");
|
||||
let banner_rendered = false;
|
||||
mock_template("compose_banner/compose_banner.hbs", false, (data) => {
|
||||
assert.equal(data.classname, compose_banner.CLASSNAMES.message_too_long);
|
||||
@@ -585,7 +584,7 @@ test_ui("test_check_overflow_text", ({mock_template}) => {
|
||||
assert.equal(limit_indicator_html, "10001​/10000\n");
|
||||
assert.ok($textarea.hasClass("over_limit"));
|
||||
assert.ok(banner_rendered);
|
||||
assert.ok($send_button.prop("disabled"));
|
||||
assert.ok($(".message-send-controls").hasClass("disabled-message-send-controls"));
|
||||
|
||||
// Indicator should show orange colored text
|
||||
banner_rendered = false;
|
||||
@@ -594,7 +593,7 @@ test_ui("test_check_overflow_text", ({mock_template}) => {
|
||||
assert.ok(!$indicator.hasClass("over_limit"));
|
||||
assert.equal(limit_indicator_html, "9001​/10000\n");
|
||||
assert.ok(!$textarea.hasClass("over_limit"));
|
||||
assert.ok(!$send_button.prop("disabled"));
|
||||
assert.ok(!$(".message-send-controls").hasClass("disabled-message-send-controls"));
|
||||
assert.ok(!banner_rendered);
|
||||
|
||||
// Indicator must be empty
|
||||
|
||||
@@ -194,7 +194,7 @@ test("show_error_message", ({mock_template}) => {
|
||||
$("#compose-send-button").prop("disabled", true);
|
||||
|
||||
upload.show_error_message({mode: "compose"}, "Error message");
|
||||
assert.equal($("#compose-send-button").prop("disabled"), false);
|
||||
assert.ok(!$(".message-send-controls").hasClass("disabled-message-send-controls"));
|
||||
assert.ok(banner_shown);
|
||||
|
||||
mock_template("compose_banner/upload_banner.hbs", false, (data) => {
|
||||
@@ -237,9 +237,9 @@ test("upload_files", async ({mock_template, override_rewire}) => {
|
||||
assert.equal(config.mode, "compose");
|
||||
});
|
||||
const config = {mode: "compose"};
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
$(".message-send-controls").removeClass("disabled-message-send-controls");
|
||||
await upload.upload_files(uppy, config, []);
|
||||
assert.ok(!$("#compose-send-button").prop("disabled"));
|
||||
assert.ok(!$(".message-send-controls").hasClass("disabled-message-send-controls"));
|
||||
|
||||
let banner_shown = false;
|
||||
mock_template("compose_banner/upload_banner.hbs", false, (data) => {
|
||||
@@ -277,7 +277,7 @@ test("upload_files", async ({mock_template, override_rewire}) => {
|
||||
$("#compose .undo_markdown_preview").on("click", () => {
|
||||
markdown_preview_hide_button_clicked = true;
|
||||
});
|
||||
$("#compose-send-button").prop("disabled", false);
|
||||
$(".message-send-controls").removeClass("disabled-message-send-controls");
|
||||
$("#compose_banners .upload_banner").remove();
|
||||
$("#compose .undo_markdown_preview").show();
|
||||
|
||||
@@ -286,7 +286,7 @@ test("upload_files", async ({mock_template, override_rewire}) => {
|
||||
banner_shown = true;
|
||||
});
|
||||
await upload.upload_files(uppy, config, files);
|
||||
assert.ok($("#compose-send-button").prop("disabled"));
|
||||
assert.ok($(".message-send-controls").hasClass("disabled-message-send-controls"));
|
||||
assert.ok(banner_shown);
|
||||
assert.ok(compose_ui_insert_syntax_and_focus_called);
|
||||
assert.ok(compose_ui_autosize_textarea_called);
|
||||
|
||||
Reference in New Issue
Block a user