mirror of https://github.com/zulip/zulip.git
compose_recipient: Convert module to TypeScript.
This commit is contained in:
parent
f16c32e3a4
commit
25ff0d4418
|
@ -73,7 +73,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/compose_fade.ts",
|
"web/src/compose_fade.ts",
|
||||||
"web/src/compose_notifications.ts",
|
"web/src/compose_notifications.ts",
|
||||||
"web/src/compose_popovers.js",
|
"web/src/compose_popovers.js",
|
||||||
"web/src/compose_recipient.js",
|
"web/src/compose_recipient.ts",
|
||||||
"web/src/compose_reply.js",
|
"web/src/compose_reply.js",
|
||||||
"web/src/compose_setup.js",
|
"web/src/compose_setup.js",
|
||||||
"web/src/compose_state.ts",
|
"web/src/compose_state.ts",
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
/* Compose box module responsible for the message's recipient */
|
/* Compose box module responsible for the message's recipient */
|
||||||
|
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import _ from "lodash";
|
import _, {isNumber} from "lodash";
|
||||||
|
import assert from "minimalistic-assert";
|
||||||
|
import type {Instance, Placement} from "tippy.js";
|
||||||
|
|
||||||
import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs";
|
import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs";
|
||||||
|
|
||||||
|
@ -10,9 +12,11 @@ import * as compose_fade from "./compose_fade";
|
||||||
import * as compose_pm_pill from "./compose_pm_pill";
|
import * as compose_pm_pill from "./compose_pm_pill";
|
||||||
import * as compose_state from "./compose_state";
|
import * as compose_state from "./compose_state";
|
||||||
import * as compose_ui from "./compose_ui";
|
import * as compose_ui from "./compose_ui";
|
||||||
|
import type {ComposePlaceholderOptions, ComposeTriggeredOptions} from "./compose_ui";
|
||||||
import * as compose_validate from "./compose_validate";
|
import * as compose_validate from "./compose_validate";
|
||||||
import * as drafts from "./drafts";
|
import * as drafts from "./drafts";
|
||||||
import * as dropdown_widget from "./dropdown_widget";
|
import * as dropdown_widget from "./dropdown_widget";
|
||||||
|
import type {Option} from "./dropdown_widget";
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
import * as narrow_state from "./narrow_state";
|
import * as narrow_state from "./narrow_state";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
|
@ -23,19 +27,29 @@ import * as sub_store from "./sub_store";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
function composing_to_current_topic_narrow() {
|
type MessageType = "stream" | "private";
|
||||||
|
type DirectMessagesOption = {
|
||||||
|
is_direct_message: boolean;
|
||||||
|
unique_id: string | number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function composing_to_current_topic_narrow(): boolean {
|
||||||
return (
|
return (
|
||||||
util.lower_same(compose_state.stream_name(), narrow_state.stream_name() || "") &&
|
util.lower_same(compose_state.stream_name(), narrow_state.stream_name() ?? "") &&
|
||||||
util.lower_same(compose_state.topic(), narrow_state.topic() || "")
|
util.lower_same(compose_state.topic(), narrow_state.topic() ?? "")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function composing_to_current_private_message_narrow() {
|
function composing_to_current_private_message_narrow(): boolean {
|
||||||
const compose_state_recipient = compose_state.private_message_recipient();
|
const compose_state_recipient = compose_state.private_message_recipient();
|
||||||
const narrow_state_recipient = narrow_state.pm_emails_string();
|
const narrow_state_recipient = narrow_state.pm_emails_string();
|
||||||
|
if (narrow_state_recipient === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
compose_state_recipient &&
|
Boolean(compose_state_recipient) &&
|
||||||
narrow_state_recipient &&
|
Boolean(narrow_state_recipient) &&
|
||||||
_.isEqual(
|
_.isEqual(
|
||||||
compose_state_recipient
|
compose_state_recipient
|
||||||
.split(",")
|
.split(",")
|
||||||
|
@ -49,7 +63,7 @@ function composing_to_current_private_message_narrow() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_narrow_to_recipient_visibility() {
|
export function update_narrow_to_recipient_visibility(): void {
|
||||||
const message_type = compose_state.get_message_type();
|
const message_type = compose_state.get_message_type();
|
||||||
if (message_type === "stream") {
|
if (message_type === "stream") {
|
||||||
const stream_exists = Boolean(compose_state.stream_id());
|
const stream_exists = Boolean(compose_state.stream_id());
|
||||||
|
@ -76,7 +90,7 @@ export function update_narrow_to_recipient_visibility() {
|
||||||
$(".narrow_to_compose_recipients").toggleClass("invisible", true);
|
$(".narrow_to_compose_recipients").toggleClass("invisible", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_fade() {
|
function update_fade(): void {
|
||||||
if (!compose_state.composing()) {
|
if (!compose_state.composing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -92,14 +106,14 @@ function update_fade() {
|
||||||
compose_fade.update_all();
|
compose_fade.update_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_on_recipient_change() {
|
export function update_on_recipient_change(): void {
|
||||||
update_fade();
|
update_fade();
|
||||||
update_narrow_to_recipient_visibility();
|
update_narrow_to_recipient_visibility();
|
||||||
drafts.update_compose_draft_count();
|
drafts.update_compose_draft_count();
|
||||||
check_posting_policy_for_compose_box();
|
check_posting_policy_for_compose_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_posting_policy_error_message() {
|
export function get_posting_policy_error_message(): string {
|
||||||
if (compose_state.selected_recipient_id === "direct") {
|
if (compose_state.selected_recipient_id === "direct") {
|
||||||
const recipients = compose_pm_pill.get_user_ids_string();
|
const recipients = compose_pm_pill.get_user_ids_string();
|
||||||
if (!people.user_can_direct_message(recipients)) {
|
if (!people.user_can_direct_message(recipients)) {
|
||||||
|
@ -110,6 +124,10 @@ export function get_posting_policy_error_message() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isNumber(compose_state.selected_recipient_id)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
const stream = sub_store.get(compose_state.selected_recipient_id);
|
const stream = sub_store.get(compose_state.selected_recipient_id);
|
||||||
if (stream && !stream_data.can_post_messages_in_stream(stream)) {
|
if (stream && !stream_data.can_post_messages_in_stream(stream)) {
|
||||||
return $t({
|
return $t({
|
||||||
|
@ -119,7 +137,7 @@ export function get_posting_policy_error_message() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function check_posting_policy_for_compose_box() {
|
export function check_posting_policy_for_compose_box(): void {
|
||||||
const banner_text = get_posting_policy_error_message();
|
const banner_text = get_posting_policy_error_message();
|
||||||
if (banner_text === "") {
|
if (banner_text === "") {
|
||||||
compose_validate.set_recipient_disallowed(false);
|
compose_validate.set_recipient_disallowed(false);
|
||||||
|
@ -135,14 +153,15 @@ export function check_posting_policy_for_compose_box() {
|
||||||
compose_banner.show_error_message(banner_text, banner_classname, $("#compose_banners"));
|
compose_banner.show_error_message(banner_text, banner_classname, $("#compose_banners"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function switch_message_type(message_type) {
|
function switch_message_type(message_type: MessageType): void {
|
||||||
$("#compose-content .alert").hide();
|
$("#compose-content .alert").hide();
|
||||||
|
|
||||||
compose_state.set_message_type(message_type);
|
compose_state.set_message_type(message_type);
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
message_type,
|
message_type,
|
||||||
stream_id: compose_state.stream_id(),
|
trigger: "switch_message_type",
|
||||||
|
stream_id: compose_state.stream_id()!,
|
||||||
topic: compose_state.topic(),
|
topic: compose_state.topic(),
|
||||||
private_message_recipient: compose_state.private_message_recipient(),
|
private_message_recipient: compose_state.private_message_recipient(),
|
||||||
};
|
};
|
||||||
|
@ -151,7 +170,7 @@ function switch_message_type(message_type) {
|
||||||
compose_ui.set_focus(opts);
|
compose_ui.set_focus(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_recipient_label(stream_id) {
|
function update_recipient_label(stream_id: number): void {
|
||||||
const stream = stream_data.get_sub_by_id(stream_id);
|
const stream = stream_data.get_sub_by_id(stream_id);
|
||||||
if (stream === undefined) {
|
if (stream === undefined) {
|
||||||
$("#compose_select_recipient_widget .dropdown_widget_value").text(
|
$("#compose_select_recipient_widget .dropdown_widget_value").text(
|
||||||
|
@ -164,7 +183,7 @@ function update_recipient_label(stream_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_compose_for_message_type(opts) {
|
export function update_compose_for_message_type(opts: ComposeTriggeredOptions): void {
|
||||||
if (opts.message_type === "stream") {
|
if (opts.message_type === "stream") {
|
||||||
$("#compose-direct-recipient").hide();
|
$("#compose-direct-recipient").hide();
|
||||||
$("#compose_recipient_box").show();
|
$("#compose_recipient_box").show();
|
||||||
|
@ -192,10 +211,10 @@ export function update_compose_for_message_type(opts) {
|
||||||
compose_banner.clear_uploads();
|
compose_banner.clear_uploads();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function on_compose_select_recipient_update() {
|
export function on_compose_select_recipient_update(): void {
|
||||||
const prev_message_type = compose_state.get_message_type();
|
const prev_message_type = compose_state.get_message_type();
|
||||||
|
|
||||||
let curr_message_type = "stream";
|
let curr_message_type: MessageType = "stream";
|
||||||
if (compose_state.selected_recipient_id === compose_state.DIRECT_MESSAGE_ID) {
|
if (compose_state.selected_recipient_id === compose_state.DIRECT_MESSAGE_ID) {
|
||||||
curr_message_type = "private";
|
curr_message_type = "private";
|
||||||
}
|
}
|
||||||
|
@ -207,20 +226,23 @@ export function on_compose_select_recipient_update() {
|
||||||
if (curr_message_type === "stream") {
|
if (curr_message_type === "stream") {
|
||||||
// Update stream name in the recipient box.
|
// Update stream name in the recipient box.
|
||||||
const stream_id = compose_state.stream_id();
|
const stream_id = compose_state.stream_id();
|
||||||
|
assert(stream_id !== undefined);
|
||||||
update_recipient_label(stream_id);
|
update_recipient_label(stream_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_on_recipient_change();
|
update_on_recipient_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function possibly_update_stream_name_in_compose(stream_id) {
|
export function possibly_update_stream_name_in_compose(stream_id: number): void {
|
||||||
if (compose_state.selected_recipient_id === stream_id) {
|
if (compose_state.selected_recipient_id === stream_id) {
|
||||||
on_compose_select_recipient_update();
|
on_compose_select_recipient_update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function item_click_callback(event, dropdown) {
|
function item_click_callback(event: JQuery.ClickEvent, dropdown: Instance): void {
|
||||||
let recipient_id = $(event.currentTarget).attr("data-unique-id");
|
const recipient_id_str = $(event.currentTarget).attr("data-unique-id");
|
||||||
|
assert(recipient_id_str !== undefined);
|
||||||
|
let recipient_id: string | number = recipient_id_str;
|
||||||
if (recipient_id !== compose_state.DIRECT_MESSAGE_ID) {
|
if (recipient_id !== compose_state.DIRECT_MESSAGE_ID) {
|
||||||
recipient_id = Number.parseInt(recipient_id, 10);
|
recipient_id = Number.parseInt(recipient_id, 10);
|
||||||
}
|
}
|
||||||
|
@ -231,8 +253,9 @@ function item_click_callback(event, dropdown) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_options_for_recipient_widget() {
|
function get_options_for_recipient_widget(): Option[] {
|
||||||
const options = stream_data.get_options_for_dropdown_widget();
|
const options: (Option | DirectMessagesOption)[] =
|
||||||
|
stream_data.get_options_for_dropdown_widget();
|
||||||
|
|
||||||
const direct_messages_option = {
|
const direct_messages_option = {
|
||||||
is_direct_message: true,
|
is_direct_message: true,
|
||||||
|
@ -251,7 +274,7 @@ function get_options_for_recipient_widget() {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
function compose_recipient_dropdown_on_show(dropdown) {
|
function compose_recipient_dropdown_on_show(dropdown: Instance): void {
|
||||||
// Offset to display dropdown above compose.
|
// Offset to display dropdown above compose.
|
||||||
let top_offset = 5;
|
let top_offset = 5;
|
||||||
const window_height = window.innerHeight;
|
const window_height = window.innerHeight;
|
||||||
|
@ -263,12 +286,12 @@ function compose_recipient_dropdown_on_show(dropdown) {
|
||||||
// pixels below compose starting from top of compose box.
|
// pixels below compose starting from top of compose box.
|
||||||
const bottom_space = window_height - recipient_input_top - search_box_and_padding_height;
|
const bottom_space = window_height - recipient_input_top - search_box_and_padding_height;
|
||||||
// Show dropdown on top / bottom based on available space.
|
// Show dropdown on top / bottom based on available space.
|
||||||
let placement = "top-start";
|
let placement: Placement = "top-start";
|
||||||
if (bottom_space > top_space) {
|
if (bottom_space > top_space) {
|
||||||
placement = "bottom-start";
|
placement = "bottom-start";
|
||||||
top_offset = -30;
|
top_offset = -30;
|
||||||
}
|
}
|
||||||
const offset = [-10, top_offset];
|
const offset: [number, number] = [-10, top_offset];
|
||||||
dropdown.setProps({placement, offset});
|
dropdown.setProps({placement, offset});
|
||||||
const height = Math.min(
|
const height = Math.min(
|
||||||
dropdown_widget.DEFAULT_DROPDOWN_HEIGHT,
|
dropdown_widget.DEFAULT_DROPDOWN_HEIGHT,
|
||||||
|
@ -278,16 +301,16 @@ function compose_recipient_dropdown_on_show(dropdown) {
|
||||||
$popper.find(".dropdown-list-wrapper").css("max-height", height + "px");
|
$popper.find(".dropdown-list-wrapper").css("max-height", height + "px");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function open_compose_recipient_dropdown() {
|
export function open_compose_recipient_dropdown(): void {
|
||||||
$("#compose_select_recipient_widget").trigger("click");
|
$("#compose_select_recipient_widget").trigger("click");
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus_compose_recipient() {
|
function focus_compose_recipient(): void {
|
||||||
$("#compose_select_recipient_widget_wrapper").trigger("focus");
|
$("#compose_select_recipient_widget_wrapper").trigger("focus");
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Since tippy triggers this on `mousedown` it is always triggered before say a `click` on `textarea`.
|
// NOTE: Since tippy triggers this on `mousedown` it is always triggered before say a `click` on `textarea`.
|
||||||
function on_hidden_callback() {
|
function on_hidden_callback(): void {
|
||||||
if (compose_state.get_message_type() === "stream") {
|
if (compose_state.get_message_type() === "stream") {
|
||||||
// Always move focus to the topic input even if it's not empty,
|
// Always move focus to the topic input even if it's not empty,
|
||||||
// since it's likely the user will want to update the topic
|
// since it's likely the user will want to update the topic
|
||||||
|
@ -302,13 +325,13 @@ function on_hidden_callback() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handle_middle_pane_transition() {
|
export function handle_middle_pane_transition(): void {
|
||||||
if (compose_state.composing) {
|
if (compose_state.composing()) {
|
||||||
update_narrow_to_recipient_visibility();
|
update_narrow_to_recipient_visibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initialize() {
|
export function initialize(): void {
|
||||||
new dropdown_widget.DropdownWidget({
|
new dropdown_widget.DropdownWidget({
|
||||||
widget_name: "compose_select_recipient",
|
widget_name: "compose_select_recipient",
|
||||||
get_options: get_options_for_recipient_widget,
|
get_options: get_options_for_recipient_widget,
|
||||||
|
@ -334,18 +357,28 @@ export function initialize() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update_placeholder_text() {
|
export function update_placeholder_text(): void {
|
||||||
// Change compose placeholder text only if compose box is open.
|
// Change compose placeholder text only if compose box is open.
|
||||||
if (!$("textarea#compose-textarea").is(":visible")) {
|
if (!$("textarea#compose-textarea").is(":visible")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const message_type = compose_state.get_message_type();
|
||||||
|
assert(message_type !== undefined);
|
||||||
|
|
||||||
const opts = {
|
let opts: ComposePlaceholderOptions;
|
||||||
message_type: compose_state.get_message_type(),
|
if (message_type === "stream") {
|
||||||
stream_id: compose_state.stream_id(),
|
const stream_id = compose_state.stream_id();
|
||||||
|
opts = {
|
||||||
|
message_type,
|
||||||
|
stream_id,
|
||||||
topic: compose_state.topic(),
|
topic: compose_state.topic(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
opts = {
|
||||||
|
message_type,
|
||||||
direct_message_user_ids: compose_pm_pill.get_user_ids(),
|
direct_message_user_ids: compose_pm_pill.get_user_ids(),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
$("textarea#compose-textarea").attr("placeholder", compose_ui.compute_placeholder_text(opts));
|
$("textarea#compose-textarea").attr("placeholder", compose_ui.compute_placeholder_text(opts));
|
||||||
}
|
}
|
|
@ -22,7 +22,7 @@ import * as stream_data from "./stream_data";
|
||||||
import * as user_status from "./user_status";
|
import * as user_status from "./user_status";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
type ComposeTriggeredOptions = {
|
export type ComposeTriggeredOptions = {
|
||||||
trigger: string;
|
trigger: string;
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
|
@ -35,7 +35,7 @@ type ComposeTriggeredOptions = {
|
||||||
private_message_recipient: string;
|
private_message_recipient: string;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
type ComposePlaceholderOptions =
|
export type ComposePlaceholderOptions =
|
||||||
| {
|
| {
|
||||||
message_type: "stream";
|
message_type: "stream";
|
||||||
stream_id: number | undefined;
|
stream_id: number | undefined;
|
||||||
|
|
|
@ -60,7 +60,7 @@ type DropdownWidgetOptions = {
|
||||||
tippy_props?: Partial<tippy.Props>;
|
tippy_props?: Partial<tippy.Props>;
|
||||||
// NOTE: Any value other than `undefined` will be rendered when class is initialized.
|
// NOTE: Any value other than `undefined` will be rendered when class is initialized.
|
||||||
default_id?: string | number;
|
default_id?: string | number;
|
||||||
unique_id_type: DataTypes;
|
unique_id_type?: DataTypes;
|
||||||
// Text to show if the current value is not in `get_options()`.
|
// Text to show if the current value is not in `get_options()`.
|
||||||
text_if_current_value_not_in_options?: string;
|
text_if_current_value_not_in_options?: string;
|
||||||
hide_search_box?: boolean;
|
hide_search_box?: boolean;
|
||||||
|
@ -90,7 +90,7 @@ export class DropdownWidget {
|
||||||
instance: tippy.Instance | undefined;
|
instance: tippy.Instance | undefined;
|
||||||
default_id: string | number | undefined;
|
default_id: string | number | undefined;
|
||||||
current_value: string | number | undefined;
|
current_value: string | number | undefined;
|
||||||
unique_id_type: DataTypes;
|
unique_id_type: DataTypes | undefined;
|
||||||
$events_container: JQuery;
|
$events_container: JQuery;
|
||||||
text_if_current_value_not_in_options: string;
|
text_if_current_value_not_in_options: string;
|
||||||
hide_search_box: boolean;
|
hide_search_box: boolean;
|
||||||
|
|
Loading…
Reference in New Issue