diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 1c774dcba2..ce6d429e6d 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -69,6 +69,7 @@ EXEMPT_FILES = make_set( "web/src/compose_fade.js", "web/src/compose_popovers.js", "web/src/compose_recipient.js", + "web/src/compose_setup.js", "web/src/compose_state.js", "web/src/compose_textarea.ts", "web/src/compose_tooltips.js", diff --git a/web/src/compose.js b/web/src/compose.js index 96cfcb133c..2514fd6156 100644 --- a/web/src/compose.js +++ b/web/src/compose.js @@ -7,41 +7,25 @@ import _ from "lodash"; import render_success_message_scheduled_banner from "../templates/compose_banner/success_message_scheduled_banner.hbs"; import * as channel from "./channel"; -import * as compose_actions from "./compose_actions"; import * as compose_banner from "./compose_banner"; import * as compose_call from "./compose_call"; -import * as compose_call_ui from "./compose_call_ui"; -import * as compose_recipient from "./compose_recipient"; import * as compose_state from "./compose_state"; import * as compose_ui from "./compose_ui"; import * as compose_validate from "./compose_validate"; import * as drafts from "./drafts"; import * as echo from "./echo"; -import * as flatpickr from "./flatpickr"; import {$t_html} from "./i18n"; import * as loading from "./loading"; import * as markdown from "./markdown"; -import * as message_edit from "./message_edit"; import * as message_events from "./message_events"; -import * as narrow from "./narrow"; import {page_params} from "./page_params"; import * as people from "./people"; import * as rendered_markdown from "./rendered_markdown"; -import * as resize from "./resize"; -import * as rows from "./rows"; import * as scheduled_messages from "./scheduled_messages"; -import * as scheduled_messages_popover from "./scheduled_messages_popover"; import * as sent_messages from "./sent_messages"; import * as server_events from "./server_events"; -import * as stream_data from "./stream_data"; -import * as stream_settings_ui from "./stream_settings_ui"; -import * as sub_store from "./sub_store"; -import * as subscriber_api from "./subscriber_api"; -import {get_timestamp_for_flatpickr} from "./timerender"; import * as transmit from "./transmit"; -import * as upload from "./upload"; import {user_settings} from "./user_settings"; -import * as user_topics from "./user_topics"; import * as util from "./util"; import * as zcommand from "./zcommand"; @@ -89,11 +73,6 @@ export function clear_preview_area() { $("#compose .preview_mode_disabled .compose_control_button").attr("tabindex", 0); } -export function abort_xhr() { - $("#compose-send-button").prop("disabled", false); - upload.compose_upload_object.cancelAll(); -} - export function create_message_object() { // Topics are optional, and we provide a placeholder if one isn't given. let topic = compose_state.topic(); @@ -378,365 +357,6 @@ export function render_and_show_preview($preview_spinner, $preview_content_box, } } -function setup_compose_actions_hooks() { - compose_actions.register_compose_box_clear_hook(clear_invites); - compose_actions.register_compose_box_clear_hook(clear_private_stream_alert); - compose_actions.register_compose_box_clear_hook(clear_preview_area); - - compose_actions.register_compose_cancel_hook(abort_xhr); - compose_actions.register_compose_cancel_hook(compose_call.abort_video_callbacks); -} - -export function initialize() { - // Register hooks for compose_actions. - setup_compose_actions_hooks(); - - $("#below-compose-content .video_link").toggle(compose_call.compute_show_video_chat_button()); - $("#below-compose-content .audio_link").toggle(compose_call.compute_show_audio_chat_button()); - - $("#compose-textarea").on("keydown", (event) => { - compose_ui.handle_keydown(event, $("#compose-textarea").expectOne()); - }); - $("#compose-textarea").on("keyup", (event) => { - compose_ui.handle_keyup(event, $("#compose-textarea").expectOne()); - }); - - $("#compose-textarea").on("input propertychange", () => { - compose_validate.warn_if_topic_resolved(false); - const compose_text_length = compose_validate.check_overflow_text(); - if (compose_text_length !== 0 && $("#compose-textarea").hasClass("invalid")) { - $("#compose-textarea").toggleClass("invalid", false); - } - // Change compose close button tooltip as per condition. - // We save compose text in draft only if its length is > 2. - if (compose_text_length > 2) { - $("#compose_close").attr( - "data-tooltip-template-id", - "compose_close_and_save_tooltip_template", - ); - } else { - $("#compose_close").attr("data-tooltip-template-id", "compose_close_tooltip_template"); - } - }); - - $("#compose form").on("submit", (e) => { - e.preventDefault(); - finish(); - }); - - resize.watch_manual_resize("#compose-textarea"); - - // Updates compose max-height and scroll to bottom button position when - // there is a change in compose height like when a compose banner is displayed. - const update_compose_max_height = new ResizeObserver(resize.reset_compose_message_max_height); - update_compose_max_height.observe(document.querySelector("#compose")); - - upload.feature_check($("#compose .compose_upload_file")); - - function get_input_info(event) { - const $edit_banners_container = $(event.target).closest(".edit_form_banners"); - const is_edit_input = Boolean($edit_banners_container.length); - const $banner_container = $edit_banners_container.length - ? $edit_banners_container - : $("#compose_banners"); - return {is_edit_input, $banner_container}; - } - - $("body").on( - "click", - `.${CSS.escape( - compose_banner.CLASSNAMES.wildcard_warning, - )} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - const {$banner_container, is_edit_input} = get_input_info(event); - const $row = $(event.target).closest(".message_row"); - compose_validate.clear_wildcard_warnings($banner_container); - compose_validate.set_user_acknowledged_wildcard_flag(true); - if (is_edit_input) { - message_edit.save_message_row_edit($row); - } else if (event.target.dataset.validationTrigger === "schedule") { - scheduled_messages_popover.open_send_later_menu(); - - // We need to set this flag to true here because `open_send_later_menu` validates the message and sets - // the user acknowledged wildcard flag back to 'false' and we don't want that to happen because then it - // would again show the wildcard warning banner when we actually send the message from 'send-later' modal. - compose_validate.set_user_acknowledged_wildcard_flag(true); - } else { - finish(); - } - }, - ); - - const user_not_subscribed_selector = `.${CSS.escape( - compose_banner.CLASSNAMES.user_not_subscribed, - )}`; - $("body").on( - "click", - `${user_not_subscribed_selector} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - - const stream_id = compose_state.stream_id(); - if (stream_id === "") { - return; - } - const sub = stream_data.get_sub_by_id(stream_id); - stream_settings_ui.sub_or_unsub(sub); - $(user_not_subscribed_selector).remove(); - }, - ); - - $("body").on( - "click", - `.${CSS.escape(compose_banner.CLASSNAMES.topic_resolved)} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - - const $target = $(event.target).parents(".main-view-banner"); - const stream_id = Number.parseInt($target.attr("data-stream-id"), 10); - const topic_name = $target.attr("data-topic-name"); - - message_edit.with_first_message_id(stream_id, topic_name, (message_id) => { - message_edit.toggle_resolve_topic(message_id, topic_name, true); - compose_validate.clear_topic_resolved_warning(true); - }); - }, - ); - - $("body").on( - "click", - `.${CSS.escape( - compose_banner.CLASSNAMES.unmute_topic_notification, - )} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - - const $target = $(event.target).parents(".main-view-banner"); - const stream_id = Number.parseInt($target.attr("data-stream-id"), 10); - const topic_name = $target.attr("data-topic-name"); - - user_topics.set_user_topic_visibility_policy( - stream_id, - topic_name, - user_topics.all_visibility_policies.UNMUTED, - false, - true, - ); - }, - ); - - $("body").on( - "click", - `.${CSS.escape( - compose_banner.CLASSNAMES.unscheduled_message, - )} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - const send_at_timestamp = scheduled_messages.get_selected_send_later_timestamp(); - scheduled_messages_popover.do_schedule_message(send_at_timestamp); - }, - ); - - $("body").on( - "click", - `.${CSS.escape( - compose_banner.CLASSNAMES.recipient_not_subscribed, - )} .main-view-banner-action-button`, - (event) => { - event.preventDefault(); - const {$banner_container} = get_input_info(event); - const $invite_row = $(event.target).parents(".main-view-banner"); - - const user_id = Number.parseInt($invite_row.data("user-id"), 10); - const stream_id = Number.parseInt($invite_row.data("stream-id"), 10); - - function success() { - $invite_row.remove(); - } - - function xhr_failure(xhr) { - let error_message = "Failed to subscribe user!"; - if (xhr.responseJSON?.msg) { - error_message = xhr.responseJSON.msg; - } - clear_invites(); - compose_banner.show_error_message( - error_message, - compose_banner.CLASSNAMES.generic_compose_error, - $banner_container, - $("#compose-textarea"), - ); - $(event.target).prop("disabled", true); - } - - const sub = sub_store.get(stream_id); - - subscriber_api.add_user_ids_to_stream([user_id], sub, success, xhr_failure); - }, - ); - - for (const classname of Object.values(compose_banner.CLASSNAMES)) { - const classname_selector = `.${CSS.escape(classname)}`; - $("body").on("click", `${classname_selector} .main-view-banner-close-button`, (event) => { - event.preventDefault(); - $(event.target).parents(classname_selector).remove(); - }); - } - - // Click event binding for "Attach files" button - // Triggers a click on a hidden file input field - - $("#compose").on("click", ".compose_upload_file", (e) => { - e.preventDefault(); - e.stopPropagation(); - - $("#compose .file_input").trigger("click"); - }); - - $("body").on("click", ".video_link", (e) => { - e.preventDefault(); - e.stopPropagation(); - - const show_video_chat_button = compose_call.compute_show_video_chat_button(); - - if (!show_video_chat_button) { - return; - } - - compose_call_ui.generate_and_insert_audio_or_video_call_link($(e.target), false); - }); - - $("body").on("click", ".audio_link", (e) => { - e.preventDefault(); - e.stopPropagation(); - - const show_audio_chat_button = compose_call.compute_show_audio_chat_button(); - - if (!show_audio_chat_button) { - return; - } - - compose_call_ui.generate_and_insert_audio_or_video_call_link($(e.target), true); - }); - - $("body").on("click", ".time_pick", (e) => { - e.preventDefault(); - e.stopPropagation(); - - let $target_textarea; - let edit_message_id; - const compose_click_target = compose_ui.get_compose_click_target(e); - if ($(compose_click_target).parents(".message_edit_form").length === 1) { - edit_message_id = rows.id($(compose_click_target).parents(".message_row")); - $target_textarea = $(`#edit_form_${CSS.escape(edit_message_id)} .message_edit_content`); - } else { - $target_textarea = $(compose_click_target).closest("form").find("textarea"); - } - - if (!flatpickr.is_open()) { - const on_timestamp_selection = (val) => { - const timestr = ` `; - compose_ui.insert_syntax_and_focus(timestr, $target_textarea); - }; - - flatpickr.show_flatpickr( - $(compose_click_target)[0], - on_timestamp_selection, - get_timestamp_for_flatpickr(), - { - // place the time picker wherever there is space and center it horizontally - position: "auto center", - // Since we want to handle close of flatpickr manually, we don't want - // flatpickr to hide automatically on clicking its trigger element. - ignoredFocusElements: [e.currentTarget], - }, - ); - } else { - flatpickr.flatpickr_instance?.close(); - } - }); - - $("#compose").on("click", ".markdown_preview", (e) => { - e.preventDefault(); - e.stopPropagation(); - - // Disable unneeded compose_control_buttons as we don't - // need them in preview mode. - $("#compose").addClass("preview_mode"); - $("#compose .preview_mode_disabled .compose_control_button").attr("tabindex", -1); - - const content = $("#compose-textarea").val(); - $("#compose-textarea").hide(); - $("#compose .markdown_preview").hide(); - $("#compose .undo_markdown_preview").show(); - $("#compose .undo_markdown_preview").trigger("focus"); - $("#compose .preview_message_area").show(); - - render_and_show_preview( - $("#compose .markdown_preview_spinner"), - $("#compose .preview_content"), - content, - ); - }); - - $("#compose").on("click", ".undo_markdown_preview", (e) => { - e.preventDefault(); - e.stopPropagation(); - - clear_preview_area(); - }); - - $("#compose").on("click", ".expand_composebox_button", (e) => { - e.preventDefault(); - e.stopPropagation(); - - compose_ui.make_compose_box_full_size(); - }); - - $("#compose").on("click", ".narrow_to_compose_recipients", (e) => { - e.preventDefault(); - narrow.to_compose_target(); - }); - - $("#compose").on("click", ".collapse_composebox_button", (e) => { - e.preventDefault(); - e.stopPropagation(); - - compose_ui.make_compose_box_original_size(); - }); - - $("#compose-textarea").on("focus", () => { - compose_recipient.update_placeholder_text(); - }); - - $("#stream_message_recipient_topic").on("focus", () => { - compose_recipient.update_placeholder_text(); - }); - - $("#stream_message_recipient_topic").on("input", () => { - compose_recipient.update_placeholder_text(); - }); - - $("body").on("click", ".formatting_button", (e) => { - const $compose_click_target = $(compose_ui.get_compose_click_target(e)); - const $textarea = $compose_click_target.closest("form").find("textarea"); - const format_type = $(e.target).attr("data-format-type"); - compose_ui.format_text($textarea, format_type); - $textarea.trigger("focus"); - e.preventDefault(); - e.stopPropagation(); - }); - - if (page_params.narrow !== undefined) { - if (page_params.narrow_topic !== undefined) { - compose_actions.start("stream", {topic: page_params.narrow_topic}); - } else { - compose_actions.start("stream", {}); - } - } -} - function schedule_message_to_custom_date() { const compose_message_object = create_message_object(); diff --git a/web/src/compose_setup.js b/web/src/compose_setup.js new file mode 100644 index 0000000000..89a466c285 --- /dev/null +++ b/web/src/compose_setup.js @@ -0,0 +1,390 @@ +import $ from "jquery"; + +import * as compose from "./compose"; +import * as compose_actions from "./compose_actions"; +import * as compose_banner from "./compose_banner"; +import * as compose_call from "./compose_call"; +import * as compose_call_ui from "./compose_call_ui"; +import * as compose_recipient from "./compose_recipient"; +import * as compose_state from "./compose_state"; +import * as compose_ui from "./compose_ui"; +import * as compose_validate from "./compose_validate"; +import * as flatpickr from "./flatpickr"; +import * as message_edit from "./message_edit"; +import * as narrow from "./narrow"; +import {page_params} from "./page_params"; +import * as resize from "./resize"; +import * as rows from "./rows"; +import * as scheduled_messages from "./scheduled_messages"; +import * as scheduled_messages_popover from "./scheduled_messages_popover"; +import * as stream_data from "./stream_data"; +import * as stream_settings_ui from "./stream_settings_ui"; +import * as sub_store from "./sub_store"; +import * as subscriber_api from "./subscriber_api"; +import {get_timestamp_for_flatpickr} from "./timerender"; +import * as upload from "./upload"; +import * as user_topics from "./user_topics"; + +export function abort_xhr() { + $("#compose-send-button").prop("disabled", false); + upload.compose_upload_object.cancelAll(); +} + +function setup_compose_actions_hooks() { + compose_actions.register_compose_box_clear_hook(compose.clear_invites); + compose_actions.register_compose_box_clear_hook(compose.clear_private_stream_alert); + compose_actions.register_compose_box_clear_hook(compose.clear_preview_area); + + compose_actions.register_compose_cancel_hook(abort_xhr); + compose_actions.register_compose_cancel_hook(compose_call.abort_video_callbacks); +} + +export function initialize() { + // Register hooks for compose_actions. + setup_compose_actions_hooks(); + + $("#below-compose-content .video_link").toggle(compose_call.compute_show_video_chat_button()); + $("#below-compose-content .audio_link").toggle(compose_call.compute_show_audio_chat_button()); + + $("#compose-textarea").on("keydown", (event) => { + compose_ui.handle_keydown(event, $("#compose-textarea").expectOne()); + }); + $("#compose-textarea").on("keyup", (event) => { + compose_ui.handle_keyup(event, $("#compose-textarea").expectOne()); + }); + + $("#compose-textarea").on("input propertychange", () => { + compose_validate.warn_if_topic_resolved(false); + const compose_text_length = compose_validate.check_overflow_text(); + if (compose_text_length !== 0 && $("#compose-textarea").hasClass("invalid")) { + $("#compose-textarea").toggleClass("invalid", false); + } + // Change compose close button tooltip as per condition. + // We save compose text in draft only if its length is > 2. + if (compose_text_length > 2) { + $("#compose_close").attr( + "data-tooltip-template-id", + "compose_close_and_save_tooltip_template", + ); + } else { + $("#compose_close").attr("data-tooltip-template-id", "compose_close_tooltip_template"); + } + }); + + $("#compose form").on("submit", (e) => { + e.preventDefault(); + compose.finish(); + }); + + resize.watch_manual_resize("#compose-textarea"); + + // Updates compose max-height and scroll to bottom button position when + // there is a change in compose height like when a compose banner is displayed. + const update_compose_max_height = new ResizeObserver(resize.reset_compose_message_max_height); + update_compose_max_height.observe(document.querySelector("#compose")); + + upload.feature_check($("#compose .compose_upload_file")); + + function get_input_info(event) { + const $edit_banners_container = $(event.target).closest(".edit_form_banners"); + const is_edit_input = Boolean($edit_banners_container.length); + const $banner_container = $edit_banners_container.length + ? $edit_banners_container + : $("#compose_banners"); + return {is_edit_input, $banner_container}; + } + + $("body").on( + "click", + `.${CSS.escape( + compose_banner.CLASSNAMES.wildcard_warning, + )} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + const {$banner_container, is_edit_input} = get_input_info(event); + const $row = $(event.target).closest(".message_row"); + compose_validate.clear_wildcard_warnings($banner_container); + compose_validate.set_user_acknowledged_wildcard_flag(true); + if (is_edit_input) { + message_edit.save_message_row_edit($row); + } else if (event.target.dataset.validationTrigger === "schedule") { + scheduled_messages_popover.open_send_later_menu(); + + // We need to set this flag to true here because `open_send_later_menu` validates the message and sets + // the user acknowledged wildcard flag back to 'false' and we don't want that to happen because then it + // would again show the wildcard warning banner when we actually send the message from 'send-later' modal. + compose_validate.set_user_acknowledged_wildcard_flag(true); + } else { + compose.finish(); + } + }, + ); + + const user_not_subscribed_selector = `.${CSS.escape( + compose_banner.CLASSNAMES.user_not_subscribed, + )}`; + $("body").on( + "click", + `${user_not_subscribed_selector} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + + const stream_id = compose_state.stream_id(); + if (stream_id === "") { + return; + } + const sub = stream_data.get_sub_by_id(stream_id); + stream_settings_ui.sub_or_unsub(sub); + $(user_not_subscribed_selector).remove(); + }, + ); + + $("body").on( + "click", + `.${CSS.escape(compose_banner.CLASSNAMES.topic_resolved)} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + + const $target = $(event.target).parents(".main-view-banner"); + const stream_id = Number.parseInt($target.attr("data-stream-id"), 10); + const topic_name = $target.attr("data-topic-name"); + + message_edit.with_first_message_id(stream_id, topic_name, (message_id) => { + message_edit.toggle_resolve_topic(message_id, topic_name, true); + compose_validate.clear_topic_resolved_warning(true); + }); + }, + ); + + $("body").on( + "click", + `.${CSS.escape( + compose_banner.CLASSNAMES.unmute_topic_notification, + )} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + + const $target = $(event.target).parents(".main-view-banner"); + const stream_id = Number.parseInt($target.attr("data-stream-id"), 10); + const topic_name = $target.attr("data-topic-name"); + + user_topics.set_user_topic_visibility_policy( + stream_id, + topic_name, + user_topics.all_visibility_policies.UNMUTED, + false, + true, + ); + }, + ); + + $("body").on( + "click", + `.${CSS.escape( + compose_banner.CLASSNAMES.unscheduled_message, + )} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + const send_at_timestamp = scheduled_messages.get_selected_send_later_timestamp(); + scheduled_messages_popover.do_schedule_message(send_at_timestamp); + }, + ); + + $("body").on( + "click", + `.${CSS.escape( + compose_banner.CLASSNAMES.recipient_not_subscribed, + )} .main-view-banner-action-button`, + (event) => { + event.preventDefault(); + const {$banner_container} = get_input_info(event); + const $invite_row = $(event.target).parents(".main-view-banner"); + + const user_id = Number.parseInt($invite_row.data("user-id"), 10); + const stream_id = Number.parseInt($invite_row.data("stream-id"), 10); + + function success() { + $invite_row.remove(); + } + + function xhr_failure(xhr) { + let error_message = "Failed to subscribe user!"; + if (xhr.responseJSON?.msg) { + error_message = xhr.responseJSON.msg; + } + compose.clear_invites(); + compose_banner.show_error_message( + error_message, + compose_banner.CLASSNAMES.generic_compose_error, + $banner_container, + $("#compose-textarea"), + ); + $(event.target).prop("disabled", true); + } + + const sub = sub_store.get(stream_id); + + subscriber_api.add_user_ids_to_stream([user_id], sub, success, xhr_failure); + }, + ); + + for (const classname of Object.values(compose_banner.CLASSNAMES)) { + const classname_selector = `.${CSS.escape(classname)}`; + $("body").on("click", `${classname_selector} .main-view-banner-close-button`, (event) => { + event.preventDefault(); + $(event.target).parents(classname_selector).remove(); + }); + } + + // Click event binding for "Attach files" button + // Triggers a click on a hidden file input field + + $("#compose").on("click", ".compose_upload_file", (e) => { + e.preventDefault(); + e.stopPropagation(); + + $("#compose .file_input").trigger("click"); + }); + + $("body").on("click", ".video_link", (e) => { + e.preventDefault(); + e.stopPropagation(); + + const show_video_chat_button = compose_call.compute_show_video_chat_button(); + + if (!show_video_chat_button) { + return; + } + + compose_call_ui.generate_and_insert_audio_or_video_call_link($(e.target), false); + }); + + $("body").on("click", ".audio_link", (e) => { + e.preventDefault(); + e.stopPropagation(); + + const show_audio_chat_button = compose_call.compute_show_audio_chat_button(); + + if (!show_audio_chat_button) { + return; + } + + compose_call_ui.generate_and_insert_audio_or_video_call_link($(e.target), true); + }); + + $("body").on("click", ".time_pick", (e) => { + e.preventDefault(); + e.stopPropagation(); + + let $target_textarea; + let edit_message_id; + const compose_click_target = compose_ui.get_compose_click_target(e); + if ($(compose_click_target).parents(".message_edit_form").length === 1) { + edit_message_id = rows.id($(compose_click_target).parents(".message_row")); + $target_textarea = $(`#edit_form_${CSS.escape(edit_message_id)} .message_edit_content`); + } else { + $target_textarea = $(compose_click_target).closest("form").find("textarea"); + } + + if (!flatpickr.is_open()) { + const on_timestamp_selection = (val) => { + const timestr = ` `; + compose_ui.insert_syntax_and_focus(timestr, $target_textarea); + }; + + flatpickr.show_flatpickr( + $(compose_click_target)[0], + on_timestamp_selection, + get_timestamp_for_flatpickr(), + { + // place the time picker wherever there is space and center it horizontally + position: "auto center", + // Since we want to handle close of flatpickr manually, we don't want + // flatpickr to hide automatically on clicking its trigger element. + ignoredFocusElements: [e.currentTarget], + }, + ); + } else { + flatpickr.flatpickr_instance?.close(); + } + }); + + $("#compose").on("click", ".markdown_preview", (e) => { + e.preventDefault(); + e.stopPropagation(); + + // Disable unneeded compose_control_buttons as we don't + // need them in preview mode. + $("#compose").addClass("preview_mode"); + $("#compose .preview_mode_disabled .compose_control_button").attr("tabindex", -1); + + const content = $("#compose-textarea").val(); + $("#compose-textarea").hide(); + $("#compose .markdown_preview").hide(); + $("#compose .undo_markdown_preview").show(); + $("#compose .undo_markdown_preview").trigger("focus"); + $("#compose .preview_message_area").show(); + + compose.render_and_show_preview( + $("#compose .markdown_preview_spinner"), + $("#compose .preview_content"), + content, + ); + }); + + $("#compose").on("click", ".undo_markdown_preview", (e) => { + e.preventDefault(); + e.stopPropagation(); + + compose.clear_preview_area(); + }); + + $("#compose").on("click", ".expand_composebox_button", (e) => { + e.preventDefault(); + e.stopPropagation(); + + compose_ui.make_compose_box_full_size(); + }); + + $("#compose").on("click", ".narrow_to_compose_recipients", (e) => { + e.preventDefault(); + narrow.to_compose_target(); + }); + + $("#compose").on("click", ".collapse_composebox_button", (e) => { + e.preventDefault(); + e.stopPropagation(); + + compose_ui.make_compose_box_original_size(); + }); + + $("#compose-textarea").on("focus", () => { + compose_recipient.update_placeholder_text(); + }); + + $("#stream_message_recipient_topic").on("focus", () => { + compose_recipient.update_placeholder_text(); + }); + + $("#stream_message_recipient_topic").on("input", () => { + compose_recipient.update_placeholder_text(); + }); + + $("body").on("click", ".formatting_button", (e) => { + const $compose_click_target = $(compose_ui.get_compose_click_target(e)); + const $textarea = $compose_click_target.closest("form").find("textarea"); + const format_type = $(e.target).attr("data-format-type"); + compose_ui.format_text($textarea, format_type); + $textarea.trigger("focus"); + e.preventDefault(); + e.stopPropagation(); + }); + + if (page_params.narrow !== undefined) { + if (page_params.narrow_topic !== undefined) { + compose_actions.start("stream", {topic: page_params.narrow_topic}); + } else { + compose_actions.start("stream", {}); + } + } +} diff --git a/web/src/ui_init.js b/web/src/ui_init.js index 9e90ccef40..da14748c60 100644 --- a/web/src/ui_init.js +++ b/web/src/ui_init.js @@ -26,6 +26,7 @@ import * as compose_closed_ui from "./compose_closed_ui"; import * as compose_pm_pill from "./compose_pm_pill"; import * as compose_popovers from "./compose_popovers"; import * as compose_recipient from "./compose_recipient"; +import * as compose_setup from "./compose_setup"; import * as compose_textarea from "./compose_textarea"; import * as compose_tooltips from "./compose_tooltips"; import * as composebox_typeahead from "./composebox_typeahead"; @@ -646,8 +647,8 @@ export function initialize_everything() { playground_data: page_params.realm_playgrounds, pygments_comparator_func: typeahead_helper.compare_language, }); - compose.initialize(); - // Typeahead must be initialized after compose.initialize() + compose_setup.initialize(); + // Typeahead must be initialized after compose_setup.initialize() composebox_typeahead.initialize({ on_enter_send: compose.finish, }); diff --git a/web/tests/compose.test.js b/web/tests/compose.test.js index e14f90d967..0195f2a679 100644 --- a/web/tests/compose.test.js +++ b/web/tests/compose.test.js @@ -56,6 +56,7 @@ const compose_closed_ui = zrequire("compose_closed_ui"); const compose_recipient = zrequire("compose_recipient"); const compose_state = zrequire("compose_state"); const compose = zrequire("compose"); +const compose_setup = zrequire("compose_setup"); const echo = zrequire("echo"); const people = zrequire("people"); const stream_data = zrequire("stream_data"); @@ -124,7 +125,7 @@ function initialize_handlers({override}) { override(page_params, "realm_video_chat_provider", 0); override(upload, "feature_check", () => {}); override(resize, "watch_manual_resize", () => {}); - compose.initialize(); + compose_setup.initialize(); } test_ui("send_message_success", ({override_rewire}) => { @@ -445,7 +446,7 @@ test_ui("initialize", ({override}) => { }); override(upload, "feature_check", () => {}); - compose.initialize(); + compose_setup.initialize(); assert.ok(resize_watch_manual_resize_checked); @@ -460,7 +461,7 @@ test_ui("initialize", ({override}) => { reset_jquery(); set_up_compose_start_mock({}); - compose.initialize(); + compose_setup.initialize(); assert.ok(compose_actions_start_checked); })(); @@ -471,16 +472,16 @@ test_ui("initialize", ({override}) => { reset_jquery(); set_up_compose_start_mock({topic: "testing"}); - compose.initialize(); + compose_setup.initialize(); assert.ok(compose_actions_start_checked); })(); (function test_abort_xhr() { reset_jquery(); - compose.initialize(); + compose_setup.initialize(); - compose.abort_xhr(); + compose_setup.abort_xhr(); assert.equal($("#compose-send-button").attr(), undefined); assert.ok(uppy_cancel_all_called); diff --git a/web/tests/compose_actions.test.js b/web/tests/compose_actions.test.js index 18c0c37750..130b66bb8f 100644 --- a/web/tests/compose_actions.test.js +++ b/web/tests/compose_actions.test.js @@ -64,7 +64,7 @@ mock_esm("../src/resize", { const people = zrequire("people"); -const compose = zrequire("compose"); +const compose_setup = zrequire("compose_setup"); const compose_state = zrequire("compose_state"); const compose_actions = zrequire("compose_actions"); const message_lists = zrequire("message_lists"); @@ -224,11 +224,11 @@ test("start", ({override, override_rewire, mock_template}) => { }; let abort_xhr_called = false; - override_rewire(compose, "abort_xhr", () => { + override_rewire(compose_setup, "abort_xhr", () => { abort_xhr_called = true; }); - compose_actions.register_compose_cancel_hook(compose.abort_xhr); + compose_actions.register_compose_cancel_hook(compose_setup.abort_xhr); $("#compose-textarea").set_height(50); assert_hidden("#compose_controls"); diff --git a/web/tests/compose_video.test.js b/web/tests/compose_video.test.js index 4a3d5b2756..195fa388ef 100644 --- a/web/tests/compose_video.test.js +++ b/web/tests/compose_video.test.js @@ -27,7 +27,8 @@ set_global( ); const server_events_dispatch = zrequire("server_events_dispatch"); -const compose = zrequire("compose"); +const compose_setup = zrequire("compose_setup"); + function stub_out_video_calls() { const $elem = $("#below-compose-content .video_link"); $elem.toggle = (show) => { @@ -73,7 +74,7 @@ test("videos", ({override}) => { stub_out_video_calls(); - compose.initialize(); + compose_setup.initialize(); (function test_no_provider_video_link_compose_clicked() { const $textarea = $.create("target-stub"); @@ -249,7 +250,7 @@ test("test_video_chat_button_toggle disabled", ({override}) => { override(upload, "feature_check", () => {}); page_params.realm_video_chat_provider = realm_available_video_chat_providers.disabled.id; - compose.initialize(); + compose_setup.initialize(); assert.equal($("#below-compose-content .video_link").visible(), false); }); @@ -258,7 +259,7 @@ test("test_video_chat_button_toggle no url", ({override}) => { page_params.realm_video_chat_provider = realm_available_video_chat_providers.jitsi_meet.id; page_params.jitsi_server_url = null; - compose.initialize(); + compose_setup.initialize(); assert.equal($("#below-compose-content .video_link").visible(), false); }); @@ -267,6 +268,6 @@ test("test_video_chat_button_toggle enabled", ({override}) => { page_params.realm_video_chat_provider = realm_available_video_chat_providers.jitsi_meet.id; page_params.realm_jitsi_server_url = "https://meet.jit.si"; - compose.initialize(); + compose_setup.initialize(); assert.equal($("#below-compose-content .video_link").visible(), true); });