mirror of https://github.com/zulip/zulip.git
web: Add setters for rewired variables.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
e2cc125583
commit
52e59a9605
|
@ -55,19 +55,27 @@ function same_recipient(a: Recipient | null, b: Recipient | null): boolean {
|
|||
/** Exported only for tests. */
|
||||
export let state: TypingStatusState | null = null;
|
||||
|
||||
export function rewire_state(value: typeof state): void {
|
||||
state = value;
|
||||
}
|
||||
|
||||
/** Exported only for tests. */
|
||||
export function stop_last_notification(worker: TypingStatusWorker): void {
|
||||
export let stop_last_notification = (worker: TypingStatusWorker): void => {
|
||||
assert(state !== null, "State object should not be null here.");
|
||||
clearTimeout(state.idle_timer);
|
||||
worker.notify_server_stop(state.current_recipient);
|
||||
state = null;
|
||||
};
|
||||
|
||||
export function rewire_stop_last_notification(value: typeof stop_last_notification): void {
|
||||
stop_last_notification = value;
|
||||
}
|
||||
|
||||
/** Exported only for tests. */
|
||||
export function start_or_extend_idle_timer(
|
||||
export let start_or_extend_idle_timer = (
|
||||
worker: TypingStatusWorker,
|
||||
typing_stopped_wait_period: number,
|
||||
): ReturnType<typeof setTimeout> {
|
||||
): ReturnType<typeof setTimeout> => {
|
||||
function on_idle_timeout(): void {
|
||||
// We don't do any real error checking here, because
|
||||
// if we've been idle, we need to tell folks, and if
|
||||
|
@ -80,6 +88,10 @@ export function start_or_extend_idle_timer(
|
|||
clearTimeout(state.idle_timer);
|
||||
}
|
||||
return setTimeout(on_idle_timeout, typing_stopped_wait_period);
|
||||
};
|
||||
|
||||
export function rewire_start_or_extend_idle_timer(value: typeof start_or_extend_idle_timer): void {
|
||||
start_or_extend_idle_timer = value;
|
||||
}
|
||||
|
||||
function set_next_start_time(current_time: number, typing_started_wait_period: number): void {
|
||||
|
@ -88,27 +100,35 @@ function set_next_start_time(current_time: number, typing_started_wait_period: n
|
|||
}
|
||||
|
||||
// Exported for tests
|
||||
export function actually_ping_server(
|
||||
export let actually_ping_server = (
|
||||
worker: TypingStatusWorker,
|
||||
recipient: Recipient,
|
||||
current_time: number,
|
||||
typing_started_wait_period: number,
|
||||
): void {
|
||||
): void => {
|
||||
worker.notify_server_start(recipient);
|
||||
set_next_start_time(current_time, typing_started_wait_period);
|
||||
};
|
||||
|
||||
export function rewire_actually_ping_server(value: typeof actually_ping_server): void {
|
||||
actually_ping_server = value;
|
||||
}
|
||||
|
||||
/** Exported only for tests. */
|
||||
export function maybe_ping_server(
|
||||
export let maybe_ping_server = (
|
||||
worker: TypingStatusWorker,
|
||||
recipient: Recipient,
|
||||
typing_started_wait_period: number,
|
||||
): void {
|
||||
): void => {
|
||||
assert(state !== null, "State object should not be null here.");
|
||||
const current_time = worker.get_current_time();
|
||||
if (current_time > state.next_send_start_time) {
|
||||
actually_ping_server(worker, recipient, current_time, typing_started_wait_period);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_maybe_ping_server(value: typeof maybe_ping_server): void {
|
||||
maybe_ping_server = value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -114,7 +114,7 @@ export function compute_active_status(): ActivityState {
|
|||
return ActivityState.IDLE;
|
||||
}
|
||||
|
||||
export function send_presence_to_server(redraw?: () => void): void {
|
||||
export let send_presence_to_server = (redraw?: () => void): void => {
|
||||
// Zulip has 2 data feeds coming from the server to the client:
|
||||
// The server_events data, and this presence feed. Data from
|
||||
// server_events is nicely serialized, but if we've been offline
|
||||
|
@ -180,6 +180,10 @@ export function send_presence_to_server(redraw?: () => void): void {
|
|||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_send_presence_to_server(value: typeof send_presence_to_server): void {
|
||||
send_presence_to_server = value;
|
||||
}
|
||||
|
||||
export function mark_client_active(): void {
|
||||
|
|
|
@ -59,7 +59,7 @@ export function clear_for_testing(): void {
|
|||
user_filter = undefined;
|
||||
}
|
||||
|
||||
export function update_presence_indicators(): void {
|
||||
export let update_presence_indicators = (): void => {
|
||||
$("[data-presence-indicator-user-id]").each(function () {
|
||||
const user_id = Number.parseInt($(this).attr("data-presence-indicator-user-id") ?? "", 10);
|
||||
assert(!Number.isNaN(user_id));
|
||||
|
@ -68,6 +68,10 @@ export function update_presence_indicators(): void {
|
|||
.removeClass("user_circle_empty user_circle_green user_circle_idle")
|
||||
.addClass(user_circle_class);
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_update_presence_indicators(value: typeof update_presence_indicators): void {
|
||||
update_presence_indicators = value;
|
||||
}
|
||||
|
||||
export function redraw_user(user_id: number): void {
|
||||
|
@ -115,7 +119,7 @@ export function render_empty_user_list_message_if_needed($container: JQuery): vo
|
|||
$container.append($(empty_list_widget_html));
|
||||
}
|
||||
|
||||
export function build_user_sidebar(): number[] | undefined {
|
||||
export let build_user_sidebar = (): number[] | undefined => {
|
||||
if (realm.realm_presence_disabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -131,6 +135,10 @@ export function build_user_sidebar(): number[] | undefined {
|
|||
render_empty_user_list_message_if_needed(buddy_list.$other_users_list);
|
||||
|
||||
return all_user_ids; // for testing
|
||||
};
|
||||
|
||||
export function rewire_build_user_sidebar(value: typeof build_user_sidebar): void {
|
||||
build_user_sidebar = value;
|
||||
}
|
||||
|
||||
function do_update_users_for_search(): void {
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as ui_report from "./ui_report";
|
|||
|
||||
export let loaded = false;
|
||||
|
||||
export function rerender_alert_words_ui(): void {
|
||||
export let rerender_alert_words_ui = (): void => {
|
||||
if (!loaded) {
|
||||
return;
|
||||
}
|
||||
|
@ -33,6 +33,10 @@ export function rerender_alert_words_ui(): void {
|
|||
...ListWidget.generic_sort_functions("alphabetic", ["word"]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_rerender_alert_words_ui(value: typeof rerender_alert_words_ui): void {
|
||||
rerender_alert_words_ui = value;
|
||||
}
|
||||
|
||||
function update_alert_word_status(status_text: string, is_error: boolean): void {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import {Filter} from "./filter";
|
||||
import {MessageListData} from "./message_list_data";
|
||||
|
||||
export const all_messages_data = new MessageListData({
|
||||
export let all_messages_data = new MessageListData({
|
||||
excludes_muted_topics: false,
|
||||
filter: new Filter([]),
|
||||
});
|
||||
|
||||
export function rewire_all_messages_data(value: typeof all_messages_data): void {
|
||||
all_messages_data = value;
|
||||
}
|
||||
|
|
|
@ -186,7 +186,11 @@ export function defaultSorter(items: string[], query: string): string[] {
|
|||
return [...beginswith, ...caseSensitive, ...caseInsensitive];
|
||||
}
|
||||
|
||||
export const MAX_ITEMS = 50;
|
||||
export let MAX_ITEMS = 50;
|
||||
|
||||
export function rewire_MAX_ITEMS(value: typeof MAX_ITEMS): void {
|
||||
MAX_ITEMS = value;
|
||||
}
|
||||
|
||||
/* TYPEAHEAD PUBLIC CLASS DEFINITION
|
||||
* ================================= */
|
||||
|
|
|
@ -58,7 +58,7 @@ export function save_old_hash(): boolean {
|
|||
return was_internal_change;
|
||||
}
|
||||
|
||||
export function update(new_hash: string): void {
|
||||
export let update = (new_hash: string): void => {
|
||||
const old_hash = window.location.hash;
|
||||
|
||||
if (!new_hash.startsWith("#")) {
|
||||
|
@ -78,6 +78,10 @@ export function update(new_hash: string): void {
|
|||
state.old_hash = old_hash;
|
||||
state.is_internal_change = true;
|
||||
window.location.hash = new_hash;
|
||||
};
|
||||
|
||||
export function rewire_update(value: typeof update): void {
|
||||
update = value;
|
||||
}
|
||||
|
||||
export function exit_overlay(): void {
|
||||
|
|
|
@ -27,8 +27,19 @@ import * as util from "./util";
|
|||
|
||||
*/
|
||||
|
||||
export const max_size_before_shrinking = 600;
|
||||
export const max_channel_size_to_show_all_subscribers = 75;
|
||||
export let max_size_before_shrinking = 600;
|
||||
|
||||
export function rewire_max_size_before_shrinking(value: typeof max_size_before_shrinking): void {
|
||||
max_size_before_shrinking = value;
|
||||
}
|
||||
|
||||
export let max_channel_size_to_show_all_subscribers = 75;
|
||||
|
||||
export function rewire_max_channel_size_to_show_all_subscribers(
|
||||
value: typeof max_channel_size_to_show_all_subscribers,
|
||||
): void {
|
||||
max_channel_size_to_show_all_subscribers = value;
|
||||
}
|
||||
|
||||
let is_searching_users = false;
|
||||
|
||||
|
@ -71,11 +82,11 @@ export function level(user_id: number): number {
|
|||
}
|
||||
}
|
||||
|
||||
export function user_matches_narrow(
|
||||
export let user_matches_narrow = (
|
||||
user_id: number,
|
||||
pm_ids: Set<number>,
|
||||
stream_id?: number | null,
|
||||
): boolean {
|
||||
): boolean => {
|
||||
if (stream_id) {
|
||||
return stream_data.is_user_subscribed(stream_id, user_id);
|
||||
}
|
||||
|
@ -83,6 +94,10 @@ export function user_matches_narrow(
|
|||
return pm_ids.has(user_id) || people.is_my_user_id(user_id);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export function rewire_user_matches_narrow(value: typeof user_matches_narrow): void {
|
||||
user_matches_narrow = value;
|
||||
}
|
||||
|
||||
export function compare_function(
|
||||
|
|
|
@ -170,7 +170,7 @@ export function send_message_success(request, data) {
|
|||
}
|
||||
}
|
||||
|
||||
export function send_message(request = create_message_object()) {
|
||||
export let send_message = (request = create_message_object()) => {
|
||||
compose_state.set_recipient_edited_manually(false);
|
||||
compose_state.set_is_content_unedited_restored_draft(false);
|
||||
if (request.type === "private") {
|
||||
|
@ -269,6 +269,10 @@ export function send_message(request = create_message_object()) {
|
|||
// taking a longtime to send.
|
||||
setTimeout(() => echo.display_slow_send_loading_spinner(message), 5000);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_send_message(value) {
|
||||
send_message = value;
|
||||
}
|
||||
|
||||
export function enter_with_preview_open(ctrl_pressed = false) {
|
||||
|
@ -287,7 +291,7 @@ export function enter_with_preview_open(ctrl_pressed = false) {
|
|||
// Common entrypoint for asking the server to send the message
|
||||
// currently drafted in the compose box, including for scheduled
|
||||
// messages.
|
||||
export function finish(scheduling_message = false) {
|
||||
export let finish = (scheduling_message = false) => {
|
||||
if (compose_ui.compose_spinner_visible) {
|
||||
// Avoid sending a message twice in parallel in races where
|
||||
// the user clicks the `Send` button very quickly twice or
|
||||
|
@ -326,6 +330,10 @@ export function finish(scheduling_message = false) {
|
|||
}
|
||||
do_post_send_tasks();
|
||||
return true;
|
||||
};
|
||||
|
||||
export function rewire_finish(value) {
|
||||
finish = value;
|
||||
}
|
||||
|
||||
export function do_post_send_tasks() {
|
||||
|
|
|
@ -70,8 +70,12 @@ function call_hooks(hooks: ComposeHook[]): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function blur_compose_inputs(): void {
|
||||
export let blur_compose_inputs = (): void => {
|
||||
$(".message_comp").find("input, textarea, button, #private_message_recipient").trigger("blur");
|
||||
};
|
||||
|
||||
export function rewire_blur_compose_inputs(value: typeof blur_compose_inputs): void {
|
||||
blur_compose_inputs = value;
|
||||
}
|
||||
|
||||
function hide_box(): void {
|
||||
|
@ -109,8 +113,12 @@ function show_compose_box(opts: ComposeActionsOpts): void {
|
|||
compose_ui.set_focus(opts_by_message_type);
|
||||
}
|
||||
|
||||
export function clear_textarea(): void {
|
||||
export let clear_textarea = (): void => {
|
||||
$("#compose").find("input[type=text], textarea").val("");
|
||||
};
|
||||
|
||||
export function rewire_clear_textarea(value: typeof clear_textarea): void {
|
||||
clear_textarea = value;
|
||||
}
|
||||
|
||||
function clear_box(): void {
|
||||
|
@ -135,7 +143,7 @@ function clear_box(): void {
|
|||
}
|
||||
|
||||
let autosize_callback_opts: ComposeActionsStartOpts;
|
||||
export function autosize_message_content(opts: ComposeActionsStartOpts): void {
|
||||
export let autosize_message_content = (opts: ComposeActionsStartOpts): void => {
|
||||
if (!compose_ui.is_expanded()) {
|
||||
autosize_callback_opts = opts;
|
||||
let has_resized_once = false;
|
||||
|
@ -157,15 +165,23 @@ export function autosize_message_content(opts: ComposeActionsStartOpts): void {
|
|||
});
|
||||
autosize($("textarea#compose-textarea"));
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_autosize_message_content(value: typeof autosize_message_content): void {
|
||||
autosize_message_content = value;
|
||||
}
|
||||
|
||||
export function expand_compose_box(): void {
|
||||
export let expand_compose_box = (): void => {
|
||||
$("#compose_close").attr("data-tooltip-template-id", "compose_close_tooltip_template");
|
||||
$("#compose_controls").hide();
|
||||
$(".message_comp").show();
|
||||
};
|
||||
|
||||
export function rewire_expand_compose_box(value: typeof expand_compose_box): void {
|
||||
expand_compose_box = value;
|
||||
}
|
||||
|
||||
export function complete_starting_tasks(opts: ComposeActionsOpts): void {
|
||||
export let complete_starting_tasks = (opts: ComposeActionsOpts): void => {
|
||||
// This is sort of a kitchen sink function, and it's called only
|
||||
// by compose.start() for now. Having this as a separate function
|
||||
// makes testing a bit easier.
|
||||
|
@ -182,6 +198,10 @@ export function complete_starting_tasks(opts: ComposeActionsOpts): void {
|
|||
if (!narrow_state.narrowed_by_reply()) {
|
||||
compose_notifications.maybe_show_one_time_interleaved_view_messages_fading_banner();
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_complete_starting_tasks(value: typeof complete_starting_tasks): void {
|
||||
complete_starting_tasks = value;
|
||||
}
|
||||
|
||||
export function maybe_scroll_up_selected_message(opts: ComposeActionsStartOpts): void {
|
||||
|
@ -246,7 +266,7 @@ function same_recipient_as_before(opts: ComposeActionsOpts): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function start(raw_opts: ComposeActionsStartOpts): void {
|
||||
export let start = (raw_opts: ComposeActionsStartOpts): void => {
|
||||
if (page_params.is_spectator) {
|
||||
spectators.login_to_access();
|
||||
return;
|
||||
|
@ -390,9 +410,13 @@ export function start(raw_opts: ComposeActionsStartOpts): void {
|
|||
resize.reset_compose_message_max_height();
|
||||
|
||||
complete_starting_tasks(opts);
|
||||
};
|
||||
|
||||
export function rewire_start(value: typeof start): void {
|
||||
start = value;
|
||||
}
|
||||
|
||||
export function cancel(): void {
|
||||
export let cancel = (): void => {
|
||||
// As user closes the compose box, restore the compose box max height
|
||||
if (compose_ui.is_expanded()) {
|
||||
compose_ui.make_compose_box_original_size();
|
||||
|
@ -420,6 +444,10 @@ export function cancel(): void {
|
|||
compose_state.set_message_type(undefined);
|
||||
compose_pm_pill.clear();
|
||||
$(document).trigger("compose_canceled.zulip");
|
||||
};
|
||||
|
||||
export function rewire_cancel(value: typeof cancel): void {
|
||||
cancel = value;
|
||||
}
|
||||
|
||||
export function on_show_navigation_view(): void {
|
||||
|
@ -440,7 +468,7 @@ export function on_show_navigation_view(): void {
|
|||
cancel();
|
||||
}
|
||||
|
||||
export function on_topic_narrow(): void {
|
||||
export let on_topic_narrow = (): void => {
|
||||
if (!compose_state.composing()) {
|
||||
// If our compose box is closed, then just
|
||||
// leave it closed, assuming that the user is
|
||||
|
@ -491,6 +519,10 @@ export function on_topic_narrow(): void {
|
|||
compose_fade.update_message_list();
|
||||
drafts.update_compose_draft_count();
|
||||
$("textarea#compose-textarea").trigger("focus");
|
||||
};
|
||||
|
||||
export function rewire_on_topic_narrow(value: typeof on_topic_narrow): void {
|
||||
on_topic_narrow = value;
|
||||
}
|
||||
|
||||
// TODO/typescript: Fill this in when converting narrow.js to typescripot.
|
||||
|
|
|
@ -91,10 +91,10 @@ export function update_or_append_banner(
|
|||
}
|
||||
}
|
||||
|
||||
export function clear_message_sent_banners(
|
||||
export let clear_message_sent_banners = (
|
||||
include_unmute_banner = true,
|
||||
skip_automatic_new_visibility_policy_banner = false,
|
||||
): void {
|
||||
): void => {
|
||||
for (const classname of Object.values(MESSAGE_SENT_CLASSNAMES)) {
|
||||
if (
|
||||
skip_automatic_new_visibility_policy_banner &&
|
||||
|
@ -115,6 +115,10 @@ export function clear_message_sent_banners(
|
|||
clear_unmute_topic_notifications();
|
||||
}
|
||||
scroll_to_message_banner_message_id = null;
|
||||
};
|
||||
|
||||
export function rewire_clear_message_sent_banners(value: typeof clear_message_sent_banners): void {
|
||||
clear_message_sent_banners = value;
|
||||
}
|
||||
|
||||
// TODO: Replace with compose_ui.hide_compose_spinner() when it is converted to ts.
|
||||
|
|
|
@ -61,7 +61,7 @@ export function get_recipient_label(message?: ComposeClosedMessage): string {
|
|||
}
|
||||
|
||||
// Exported for tests
|
||||
export function update_reply_button_state(disable = false): void {
|
||||
export let update_reply_button_state = (disable = false): void => {
|
||||
$(".compose_reply_button").attr("disabled", disable ? "disabled" : null);
|
||||
if (disable) {
|
||||
$("#compose_buttons .compose-reply-button-wrapper").attr(
|
||||
|
@ -81,6 +81,10 @@ export function update_reply_button_state(disable = false): void {
|
|||
"selected_conversation",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_update_reply_button_state(value: typeof update_reply_button_state): void {
|
||||
update_reply_button_state = value;
|
||||
}
|
||||
|
||||
function update_buttons(disable_reply?: boolean): void {
|
||||
|
|
|
@ -63,10 +63,14 @@ export function set_from_typeahead(person: User): void {
|
|||
});
|
||||
}
|
||||
|
||||
export function set_from_emails(value: string): void {
|
||||
export let set_from_emails = (value: string): void => {
|
||||
// value is something like "alice@example.com,bob@example.com"
|
||||
clear();
|
||||
widget.appendValue(value);
|
||||
};
|
||||
|
||||
export function rewire_set_from_emails(value: typeof set_from_emails): void {
|
||||
set_from_emails = value;
|
||||
}
|
||||
|
||||
export function get_user_ids(): number[] {
|
||||
|
@ -84,11 +88,15 @@ export function get_user_ids_string(): string {
|
|||
return user_ids_string;
|
||||
}
|
||||
|
||||
export function get_emails(): string {
|
||||
export let get_emails = (): string => {
|
||||
// return something like "alice@example.com,bob@example.com"
|
||||
const user_ids = get_user_ids();
|
||||
const emails = user_ids.map((id) => people.get_by_user_id(id).email).join(",");
|
||||
return emails;
|
||||
};
|
||||
|
||||
export function rewire_get_emails(value: typeof get_emails): void {
|
||||
get_emails = value;
|
||||
}
|
||||
|
||||
export function filter_taken_users(persons: User[]): User[] {
|
||||
|
|
|
@ -62,7 +62,7 @@ function composing_to_current_private_message_narrow(): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function update_narrow_to_recipient_visibility(): void {
|
||||
export let update_narrow_to_recipient_visibility = (): void => {
|
||||
const message_type = compose_state.get_message_type();
|
||||
if (message_type === "stream") {
|
||||
const stream_exists = Boolean(compose_state.stream_id());
|
||||
|
@ -87,6 +87,12 @@ export function update_narrow_to_recipient_visibility(): void {
|
|||
}
|
||||
}
|
||||
$(".conversation-arrow").toggleClass("narrow_to_compose_recipients", false);
|
||||
};
|
||||
|
||||
export function rewire_update_narrow_to_recipient_visibility(
|
||||
value: typeof update_narrow_to_recipient_visibility,
|
||||
): void {
|
||||
update_narrow_to_recipient_visibility = value;
|
||||
}
|
||||
|
||||
function update_fade(): void {
|
||||
|
@ -131,7 +137,7 @@ export function get_posting_policy_error_message(): string {
|
|||
return "";
|
||||
}
|
||||
|
||||
export function check_posting_policy_for_compose_box(): void {
|
||||
export let check_posting_policy_for_compose_box = (): void => {
|
||||
const banner_text = get_posting_policy_error_message();
|
||||
if (banner_text === "") {
|
||||
compose_validate.set_recipient_disallowed(false);
|
||||
|
@ -147,6 +153,12 @@ export function check_posting_policy_for_compose_box(): void {
|
|||
} else {
|
||||
compose_banner.show_error_message(banner_text, banner_classname, $("#compose_banners"));
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_check_posting_policy_for_compose_box(
|
||||
value: typeof check_posting_policy_for_compose_box,
|
||||
): void {
|
||||
check_posting_policy_for_compose_box = value;
|
||||
}
|
||||
|
||||
function switch_message_type(message_type: MessageType): void {
|
||||
|
@ -207,7 +219,7 @@ export function update_compose_for_message_type(opts: ComposeTriggeredOptions):
|
|||
compose_banner.clear_uploads();
|
||||
}
|
||||
|
||||
export function on_compose_select_recipient_update(): void {
|
||||
export let on_compose_select_recipient_update = (): void => {
|
||||
const prev_message_type = compose_state.get_message_type();
|
||||
|
||||
let curr_message_type: MessageType = "stream";
|
||||
|
@ -226,6 +238,12 @@ export function on_compose_select_recipient_update(): void {
|
|||
}
|
||||
|
||||
update_on_recipient_change();
|
||||
};
|
||||
|
||||
export function rewire_on_compose_select_recipient_update(
|
||||
value: typeof on_compose_select_recipient_update,
|
||||
): void {
|
||||
on_compose_select_recipient_update = value;
|
||||
}
|
||||
|
||||
export function possibly_update_stream_name_in_compose(stream_id: number): void {
|
||||
|
@ -327,7 +345,7 @@ export function initialize(): void {
|
|||
});
|
||||
}
|
||||
|
||||
export function update_placeholder_text(): void {
|
||||
export let update_placeholder_text = (): void => {
|
||||
const $textarea: JQuery<HTMLTextAreaElement> = $("textarea#compose-textarea");
|
||||
// Change compose placeholder text only if compose box is open.
|
||||
if (!$textarea.is(":visible")) {
|
||||
|
@ -352,4 +370,8 @@ export function update_placeholder_text(): void {
|
|||
|
||||
$textarea.attr("placeholder", placeholder);
|
||||
compose_ui.autosize_textarea($textarea);
|
||||
};
|
||||
|
||||
export function rewire_update_placeholder_text(value: typeof update_placeholder_text): void {
|
||||
update_placeholder_text = value;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ import * as recent_view_util from "./recent_view_util";
|
|||
import * as stream_data from "./stream_data";
|
||||
import * as unread_ops from "./unread_ops";
|
||||
|
||||
export function respond_to_message(opts: {
|
||||
export let respond_to_message = (opts: {
|
||||
keep_composebox_empty?: boolean;
|
||||
message_id?: number;
|
||||
reply_type?: "personal";
|
||||
trigger?: string;
|
||||
}): void {
|
||||
}): void => {
|
||||
let message;
|
||||
let msg_type: "private" | "stream";
|
||||
if (recent_view_util.is_visible()) {
|
||||
|
@ -147,6 +147,10 @@ export function respond_to_message(opts: {
|
|||
is_reply: true,
|
||||
keep_composebox_empty: opts.keep_composebox_empty,
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_respond_to_message(value: typeof respond_to_message): void {
|
||||
respond_to_message = value;
|
||||
}
|
||||
|
||||
export function reply_with_mention(opts: {
|
||||
|
@ -166,7 +170,9 @@ export function reply_with_mention(opts: {
|
|||
compose_ui.insert_syntax_and_focus(mention);
|
||||
}
|
||||
|
||||
export function selection_within_message_id(selection = window.getSelection()): number | undefined {
|
||||
export let selection_within_message_id = (
|
||||
selection = window.getSelection(),
|
||||
): number | undefined => {
|
||||
// Returns the message_id if the selection is entirely within a message,
|
||||
// otherwise returns undefined.
|
||||
assert(selection !== null);
|
||||
|
@ -178,6 +184,12 @@ export function selection_within_message_id(selection = window.getSelection()):
|
|||
return start_id;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export function rewire_selection_within_message_id(
|
||||
value: typeof selection_within_message_id,
|
||||
): void {
|
||||
selection_within_message_id = value;
|
||||
}
|
||||
|
||||
function get_quote_target(opts: {message_id?: number; quote_content?: string}): {
|
||||
|
|
|
@ -106,12 +106,16 @@ export function stream_id(): number | undefined {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function stream_name(): string {
|
||||
export let stream_name = (): string => {
|
||||
const stream_id = selected_recipient_id;
|
||||
if (typeof stream_id === "number") {
|
||||
return sub_store.maybe_get_stream_name(stream_id) ?? "";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
export function rewire_stream_name(value: typeof stream_name): void {
|
||||
stream_name = value;
|
||||
}
|
||||
|
||||
export function set_stream_id(stream_id: number | ""): void {
|
||||
|
|
|
@ -70,6 +70,11 @@ const message_render_response_schema = z.object({
|
|||
});
|
||||
|
||||
export let compose_spinner_visible = false;
|
||||
|
||||
export function rewire_compose_spinner_visible(value: typeof compose_spinner_visible): void {
|
||||
compose_spinner_visible = value;
|
||||
}
|
||||
|
||||
export let shift_pressed = false; // true or false
|
||||
export let code_formatting_button_triggered = false; // true or false
|
||||
export let compose_textarea_typeahead: Typeahead<TypeaheadSuggestion> | undefined;
|
||||
|
@ -102,20 +107,24 @@ export function is_full_size(): boolean {
|
|||
return full_size_status;
|
||||
}
|
||||
|
||||
export function autosize_textarea($textarea: JQuery<HTMLTextAreaElement>): void {
|
||||
export let autosize_textarea = ($textarea: JQuery<HTMLTextAreaElement>): void => {
|
||||
// Since this supports both compose and file upload, one must pass
|
||||
// in the text area to autosize.
|
||||
if (!is_expanded()) {
|
||||
autosize.update($textarea);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_autosize_textarea(value: typeof autosize_textarea): void {
|
||||
autosize_textarea = value;
|
||||
}
|
||||
|
||||
export function insert_and_scroll_into_view(
|
||||
export let insert_and_scroll_into_view = (
|
||||
content: string,
|
||||
$textarea: JQuery<HTMLTextAreaElement>,
|
||||
replace_all = false,
|
||||
replace_all_without_undo_support = false,
|
||||
): void {
|
||||
): void => {
|
||||
if (replace_all_without_undo_support) {
|
||||
// setFieldText is very slow and noticeable when inserting 10k+
|
||||
// characters of text like from a drafted response,
|
||||
|
@ -132,6 +141,12 @@ export function insert_and_scroll_into_view(
|
|||
$textarea.trigger("blur");
|
||||
$textarea.trigger("focus");
|
||||
autosize_textarea($textarea);
|
||||
};
|
||||
|
||||
export function rewire_insert_and_scroll_into_view(
|
||||
value: typeof insert_and_scroll_into_view,
|
||||
): void {
|
||||
insert_and_scroll_into_view = value;
|
||||
}
|
||||
|
||||
function get_focus_area(opts: ComposeTriggeredOptions): string {
|
||||
|
@ -168,7 +183,7 @@ export function set_focus(opts: ComposeTriggeredOptions): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function smart_insert_inline($textarea: JQuery<HTMLTextAreaElement>, syntax: string): void {
|
||||
export let smart_insert_inline = ($textarea: JQuery<HTMLTextAreaElement>, syntax: string): void => {
|
||||
function is_space(c: string | undefined): boolean {
|
||||
return c === " " || c === "\t" || c === "\n";
|
||||
}
|
||||
|
@ -200,6 +215,10 @@ export function smart_insert_inline($textarea: JQuery<HTMLTextAreaElement>, synt
|
|||
}
|
||||
|
||||
insert_and_scroll_into_view(syntax, $textarea);
|
||||
};
|
||||
|
||||
export function rewire_smart_insert_inline(value: typeof smart_insert_inline): void {
|
||||
smart_insert_inline = value;
|
||||
}
|
||||
|
||||
export function smart_insert_block(
|
||||
|
@ -252,12 +271,12 @@ export function smart_insert_block(
|
|||
insert_and_scroll_into_view(syntax, $textarea);
|
||||
}
|
||||
|
||||
export function insert_syntax_and_focus(
|
||||
export let insert_syntax_and_focus = (
|
||||
syntax: string,
|
||||
$textarea = $<HTMLTextAreaElement>("textarea#compose-textarea"),
|
||||
mode = "inline",
|
||||
padding_newlines?: number,
|
||||
): void {
|
||||
): void => {
|
||||
// Generic helper for inserting syntax into the main compose box
|
||||
// where the cursor was and focusing the area. Mostly a thin
|
||||
// wrapper around smart_insert_inline and smart_inline_block.
|
||||
|
@ -277,13 +296,17 @@ export function insert_syntax_and_focus(
|
|||
} else if (mode === "block") {
|
||||
smart_insert_block($textarea, syntax, padding_newlines);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_insert_syntax_and_focus(value: typeof insert_syntax_and_focus): void {
|
||||
insert_syntax_and_focus = value;
|
||||
}
|
||||
|
||||
export function replace_syntax(
|
||||
export let replace_syntax = (
|
||||
old_syntax: string,
|
||||
new_syntax: string,
|
||||
$textarea = $<HTMLTextAreaElement>("textarea#compose-textarea"),
|
||||
): boolean {
|
||||
): boolean => {
|
||||
// The following couple lines are needed to later restore the initial
|
||||
// logical position of the cursor after the replacement
|
||||
const prev_caret = $textarea.caret();
|
||||
|
@ -322,6 +345,10 @@ export function replace_syntax(
|
|||
|
||||
// Return if anything was actually replaced.
|
||||
return old_text !== new_text;
|
||||
};
|
||||
|
||||
export function rewire_replace_syntax(value: typeof replace_syntax): void {
|
||||
replace_syntax = value;
|
||||
}
|
||||
|
||||
export function compute_placeholder_text(opts: ComposePlaceholderOptions): string {
|
||||
|
@ -374,7 +401,7 @@ export function compute_placeholder_text(opts: ComposePlaceholderOptions): strin
|
|||
return DEFAULT_COMPOSE_PLACEHOLDER;
|
||||
}
|
||||
|
||||
export function set_compose_box_top(set_top: boolean): void {
|
||||
export let set_compose_box_top = (set_top: boolean): void => {
|
||||
if (set_top) {
|
||||
// As `#compose` has `position: fixed` property, we cannot
|
||||
// make the compose-box to attain the correct height just by
|
||||
|
@ -386,6 +413,10 @@ export function set_compose_box_top(set_top: boolean): void {
|
|||
} else {
|
||||
$("#compose").css("top", "");
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_set_compose_box_top(value: typeof set_compose_box_top): void {
|
||||
set_compose_box_top = value;
|
||||
}
|
||||
|
||||
export function make_compose_box_full_size(): void {
|
||||
|
@ -504,11 +535,11 @@ export function position_inside_code_block(content: string, position: number): b
|
|||
return [...code_blocks].some((code_block) => code_block?.textContent?.includes(unique_insert));
|
||||
}
|
||||
|
||||
export function format_text(
|
||||
export let format_text = (
|
||||
$textarea: JQuery<HTMLTextAreaElement>,
|
||||
type: string,
|
||||
inserted_content = "",
|
||||
): void {
|
||||
): void => {
|
||||
const italic_syntax = "*";
|
||||
const bold_syntax = "**";
|
||||
const bold_and_italic_syntax = "***";
|
||||
|
@ -1156,6 +1187,10 @@ export function format_text(
|
|||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_format_text(value: typeof format_text): void {
|
||||
format_text = value;
|
||||
}
|
||||
|
||||
/* TODO: This functions don't belong in this module, as they have
|
||||
|
|
|
@ -476,7 +476,7 @@ function is_recipient_large_topic(): boolean {
|
|||
}
|
||||
|
||||
// Exported for tests
|
||||
export function wildcard_mention_policy_authorizes_user(): boolean {
|
||||
export let wildcard_mention_policy_authorizes_user = (): boolean => {
|
||||
if (
|
||||
realm.realm_wildcard_mention_policy ===
|
||||
settings_config.wildcard_mention_policy_values.by_everyone.code
|
||||
|
@ -518,6 +518,12 @@ export function wildcard_mention_policy_authorizes_user(): boolean {
|
|||
return days >= realm.realm_waiting_period_threshold && !current_user.is_guest;
|
||||
}
|
||||
return !current_user.is_guest;
|
||||
};
|
||||
|
||||
export function rewire_wildcard_mention_policy_authorizes_user(
|
||||
value: typeof wildcard_mention_policy_authorizes_user,
|
||||
): void {
|
||||
wildcard_mention_policy_authorizes_user = value;
|
||||
}
|
||||
|
||||
export function stream_wildcard_mention_allowed(): boolean {
|
||||
|
|
|
@ -106,7 +106,11 @@ export type TypeaheadSuggestion =
|
|||
| SlashCommandSuggestion;
|
||||
|
||||
// We export it to allow tests to mock it.
|
||||
export const max_num_items = MAX_ITEMS;
|
||||
export let max_num_items = MAX_ITEMS;
|
||||
|
||||
export function rewire_max_num_items(value: typeof max_num_items): void {
|
||||
max_num_items = value;
|
||||
}
|
||||
|
||||
export let emoji_collection: Emoji[] = [];
|
||||
|
||||
|
@ -389,9 +393,13 @@ function handle_keyup(e: JQuery.KeyUpEvent): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function split_at_cursor(query: string, $input: JQuery): [string, string] {
|
||||
export let split_at_cursor = (query: string, $input: JQuery): [string, string] => {
|
||||
const cursor = $input.caret();
|
||||
return [query.slice(0, cursor), query.slice(cursor)];
|
||||
};
|
||||
|
||||
export function rewire_split_at_cursor(value: typeof split_at_cursor): void {
|
||||
split_at_cursor = value;
|
||||
}
|
||||
|
||||
export function tokenize_compose_str(s: string): string {
|
||||
|
|
|
@ -22,9 +22,13 @@ import * as timerender from "./timerender";
|
|||
import * as ui_util from "./ui_util";
|
||||
import * as util from "./util";
|
||||
|
||||
export function set_count(count: number): void {
|
||||
export let set_count = (count: number): void => {
|
||||
const $drafts_li = $(".top_left_drafts");
|
||||
ui_util.update_unread_count_in_dom($drafts_li, count);
|
||||
};
|
||||
|
||||
export function rewire_set_count(value: typeof set_count): void {
|
||||
set_count = value;
|
||||
}
|
||||
|
||||
function getTimestamp(): number {
|
||||
|
@ -219,7 +223,7 @@ export const draft_model = (function () {
|
|||
};
|
||||
})();
|
||||
|
||||
export function update_compose_draft_count(): void {
|
||||
export let update_compose_draft_count = (): void => {
|
||||
const $count_container = $(".compose-drafts-count-container");
|
||||
const $count_ele = $count_container.find(".compose-drafts-count");
|
||||
if (!compose_state.has_full_recipient()) {
|
||||
|
@ -235,11 +239,19 @@ export function update_compose_draft_count(): void {
|
|||
$count_ele.text("");
|
||||
$count_container.hide();
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_update_compose_draft_count(value: typeof update_compose_draft_count): void {
|
||||
update_compose_draft_count = value;
|
||||
}
|
||||
|
||||
export function sync_count(): void {
|
||||
export let sync_count = (): void => {
|
||||
const drafts = draft_model.get();
|
||||
set_count(Object.keys(drafts).length);
|
||||
};
|
||||
|
||||
export function rewire_sync_count(value: typeof sync_count): void {
|
||||
sync_count = value;
|
||||
}
|
||||
|
||||
export function delete_all_drafts(): void {
|
||||
|
@ -396,7 +408,7 @@ type UpdateDraftOptions = {
|
|||
is_sending_saving?: boolean;
|
||||
};
|
||||
|
||||
export function update_draft(opts: UpdateDraftOptions = {}): string | undefined {
|
||||
export let update_draft = (opts: UpdateDraftOptions = {}): string | undefined => {
|
||||
const draft_id = compose_draft_id;
|
||||
const old_draft = draft_id === undefined ? undefined : draft_model.getDraft(draft_id);
|
||||
|
||||
|
@ -439,6 +451,10 @@ export function update_draft(opts: UpdateDraftOptions = {}): string | undefined
|
|||
maybe_notify(no_notify);
|
||||
|
||||
return new_draft_id;
|
||||
};
|
||||
|
||||
export function rewire_update_draft(value: typeof update_draft): void {
|
||||
update_draft = value;
|
||||
}
|
||||
|
||||
export const DRAFT_LIFETIME = 30;
|
||||
|
|
|
@ -288,14 +288,14 @@ export function is_slash_command(content: string): boolean {
|
|||
return !content.startsWith("/me") && content.startsWith("/");
|
||||
}
|
||||
|
||||
export function try_deliver_locally(
|
||||
export let try_deliver_locally = (
|
||||
message_request: MessageRequest,
|
||||
insert_new_messages: (
|
||||
messages: LocalMessage[],
|
||||
send_by_this_client: boolean,
|
||||
deliver_locally: boolean,
|
||||
) => Message[],
|
||||
): Message | undefined {
|
||||
): Message | undefined => {
|
||||
// Checks if the message request can be locally echoed, and if so,
|
||||
// adds a local echoed copy of the message to appropriate message lists.
|
||||
//
|
||||
|
@ -349,6 +349,10 @@ export function try_deliver_locally(
|
|||
|
||||
const message = insert_local_message(message_request, local_id_float, insert_new_messages);
|
||||
return message;
|
||||
};
|
||||
|
||||
export function rewire_try_deliver_locally(value: typeof try_deliver_locally): void {
|
||||
try_deliver_locally = value;
|
||||
}
|
||||
|
||||
export function edit_locally(message: Message, request: LocalEditRequest): Message {
|
||||
|
@ -432,7 +436,7 @@ export function edit_locally(message: Message, request: LocalEditRequest): Messa
|
|||
return message;
|
||||
}
|
||||
|
||||
export function reify_message_id(local_id: string, server_id: number): void {
|
||||
export let reify_message_id = (local_id: string, server_id: number): void => {
|
||||
const message = echo_state.get_message_waiting_for_id(local_id);
|
||||
echo_state.remove_message_from_waiting_for_id(local_id);
|
||||
|
||||
|
@ -463,6 +467,10 @@ export function reify_message_id(local_id: string, server_id: number): void {
|
|||
message_id: message.id,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_reify_message_id(value: typeof reify_message_id): void {
|
||||
reify_message_id = value;
|
||||
}
|
||||
|
||||
export function update_message_lists({old_id, new_id}: {old_id: number; new_id: number}): void {
|
||||
|
@ -576,13 +584,17 @@ export function process_from_server(messages: ServerMessage[]): ServerMessage[]
|
|||
return non_echo_messages;
|
||||
}
|
||||
|
||||
export function message_send_error(message_id: number, error_response: string): void {
|
||||
export let message_send_error = (message_id: number, error_response: string): void => {
|
||||
// Error sending message, show inline
|
||||
const message = message_store.get(message_id)!;
|
||||
message.failed_request = true;
|
||||
message.show_slow_send_spinner = false;
|
||||
|
||||
show_message_failed(message_id, error_response);
|
||||
};
|
||||
|
||||
export function rewire_message_send_error(value: typeof message_send_error): void {
|
||||
message_send_error = value;
|
||||
}
|
||||
|
||||
function abort_message(message: Message): void {
|
||||
|
|
|
@ -250,7 +250,7 @@ export function get_keypress_hotkey(e) {
|
|||
return keypress_mappings[e.which];
|
||||
}
|
||||
|
||||
export function processing_text() {
|
||||
export let processing_text = () => {
|
||||
const $focused_elt = $(":focus");
|
||||
return (
|
||||
$focused_elt.is("input") ||
|
||||
|
@ -260,6 +260,10 @@ export function processing_text() {
|
|||
$focused_elt.attr("id") === "compose-send-button" ||
|
||||
$focused_elt.parents(".dropdown-list-container").length >= 1
|
||||
);
|
||||
};
|
||||
|
||||
export function rewire_processing_text(value) {
|
||||
processing_text = value;
|
||||
}
|
||||
|
||||
export function in_content_editable_widget(e) {
|
||||
|
|
|
@ -103,11 +103,11 @@ export function update_current_view_for_topic_visibility() {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function update_views_filtered_on_message_property(
|
||||
export let update_views_filtered_on_message_property = (
|
||||
message_ids,
|
||||
property_term_type,
|
||||
property_value,
|
||||
) {
|
||||
) => {
|
||||
// NOTE: Call this function after updating the message property locally.
|
||||
assert(!property_term_type.includes("not-"));
|
||||
|
||||
|
@ -212,6 +212,7 @@ export function update_views_filtered_on_message_property(
|
|||
// can be used to update other message lists and
|
||||
// cached message data structures as well.
|
||||
},
|
||||
// eslint-disable-next-line no-loop-func
|
||||
success(data) {
|
||||
// `messages_to_fetch` might already be cached locally when
|
||||
// we reach here but `message_helper.process_new_message`
|
||||
|
@ -258,6 +259,10 @@ export function update_views_filtered_on_message_property(
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_update_views_filtered_on_message_property(value) {
|
||||
update_views_filtered_on_message_property = value;
|
||||
}
|
||||
|
||||
export function insert_new_messages(messages, sent_by_this_client, deliver_locally) {
|
||||
|
|
|
@ -16,7 +16,11 @@ export function send_flag_update_for_messages(msg_ids: number[], flag: string, o
|
|||
},
|
||||
});
|
||||
}
|
||||
export const _unread_batch_size = 1000;
|
||||
export let _unread_batch_size = 1000;
|
||||
|
||||
export function rewire__unread_batch_size(value: typeof _unread_batch_size): void {
|
||||
_unread_batch_size = value;
|
||||
}
|
||||
|
||||
export const send_read = (function () {
|
||||
let queue: Message[] = [];
|
||||
|
|
|
@ -351,7 +351,7 @@ type ShowMessageViewOpts = {
|
|||
show_more_topics?: boolean;
|
||||
};
|
||||
|
||||
export function show(raw_terms: NarrowTerm[], show_opts: ShowMessageViewOpts): void {
|
||||
export let show = (raw_terms: NarrowTerm[], show_opts: ShowMessageViewOpts): void => {
|
||||
/* Main entry point for switching to a new view / message list.
|
||||
|
||||
Supported parameters:
|
||||
|
@ -777,6 +777,10 @@ export function show(raw_terms: NarrowTerm[], show_opts: ShowMessageViewOpts): v
|
|||
resize.resize_stream_filters_container();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_show(value: typeof show): void {
|
||||
show = value;
|
||||
}
|
||||
|
||||
function navigate_to_anchor_message(opts: {
|
||||
|
|
|
@ -114,7 +114,7 @@ export function set_compose_defaults(): {
|
|||
return opts;
|
||||
}
|
||||
|
||||
export function stream_id(current_filter: Filter | undefined = filter()): number | undefined {
|
||||
export let stream_id = (current_filter: Filter | undefined = filter()): number | undefined => {
|
||||
if (current_filter === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -123,6 +123,10 @@ export function stream_id(current_filter: Filter | undefined = filter()): number
|
|||
return Number.parseInt(stream_operands[0], 10);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export function rewire_stream_id(value: typeof stream_id): void {
|
||||
stream_id = value;
|
||||
}
|
||||
|
||||
export function stream_name(current_filter: Filter | undefined = filter()): string | undefined {
|
||||
|
@ -148,7 +152,7 @@ export function stream_sub(
|
|||
return stream_data.get_sub_by_id_string(stream_operands[0]);
|
||||
}
|
||||
|
||||
export function topic(current_filter: Filter | undefined = filter()): string | undefined {
|
||||
export let topic = (current_filter: Filter | undefined = filter()): string | undefined => {
|
||||
if (current_filter === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -157,6 +161,10 @@ export function topic(current_filter: Filter | undefined = filter()): string | u
|
|||
return operands[0];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export function rewire_topic(value: typeof topic): void {
|
||||
topic = value;
|
||||
}
|
||||
|
||||
export function pm_ids_string(filter?: Filter): string | undefined {
|
||||
|
@ -173,10 +181,14 @@ export function pm_ids_string(filter?: Filter): string | undefined {
|
|||
return user_ids_string;
|
||||
}
|
||||
|
||||
export function pm_ids_set(filter?: Filter): Set<number> {
|
||||
export let pm_ids_set = (filter?: Filter): Set<number> => {
|
||||
const ids_string = pm_ids_string(filter);
|
||||
const pm_ids_list = ids_string ? people.user_ids_string_to_ids_array(ids_string) : [];
|
||||
return new Set(pm_ids_list);
|
||||
};
|
||||
|
||||
export function rewire_pm_ids_set(value: typeof pm_ids_set): void {
|
||||
pm_ids_set = value;
|
||||
}
|
||||
|
||||
export function pm_emails_string(
|
||||
|
@ -194,9 +206,9 @@ export function pm_emails_string(
|
|||
return operands[0];
|
||||
}
|
||||
|
||||
export function get_first_unread_info(
|
||||
export let get_first_unread_info = (
|
||||
current_filter: Filter | undefined = filter(),
|
||||
): {flavor: "cannot_compute" | "not_found"} | {flavor: "found"; msg_id: number} {
|
||||
): {flavor: "cannot_compute" | "not_found"} | {flavor: "found"; msg_id: number} => {
|
||||
const cannot_compute_response: {flavor: "cannot_compute"} = {flavor: "cannot_compute"};
|
||||
if (current_filter === undefined) {
|
||||
// we don't yet support the all-messages view
|
||||
|
@ -231,11 +243,15 @@ export function get_first_unread_info(
|
|||
flavor: "found",
|
||||
msg_id,
|
||||
};
|
||||
};
|
||||
|
||||
export function rewire_get_first_unread_info(value: typeof get_first_unread_info): void {
|
||||
get_first_unread_info = value;
|
||||
}
|
||||
|
||||
export function _possible_unread_message_ids(
|
||||
export let _possible_unread_message_ids = (
|
||||
current_filter: Filter | undefined = filter(),
|
||||
): number[] | undefined {
|
||||
): number[] | undefined => {
|
||||
// This function currently only returns valid results for
|
||||
// certain types of narrows, mostly left sidebar narrows.
|
||||
// For more complicated narrows we may return undefined.
|
||||
|
@ -318,6 +334,12 @@ export function _possible_unread_message_ids(
|
|||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export function rewire__possible_unread_message_ids(
|
||||
value: typeof _possible_unread_message_ids,
|
||||
): void {
|
||||
_possible_unread_message_ids = value;
|
||||
}
|
||||
|
||||
// Are we narrowed to direct messages: the direct message feed or a
|
||||
|
|
|
@ -69,7 +69,7 @@ export function potential_subscribers(stream_id: number): User[] {
|
|||
return people.filter_all_users(is_potential_subscriber);
|
||||
}
|
||||
|
||||
export function get_subscriber_count(stream_id: number, include_bots = true): number {
|
||||
export let get_subscriber_count = (stream_id: number, include_bots = true): number => {
|
||||
if (include_bots) {
|
||||
return get_user_set(stream_id).size;
|
||||
}
|
||||
|
@ -81,6 +81,10 @@ export function get_subscriber_count(stream_id: number, include_bots = true): nu
|
|||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
export function rewire_get_subscriber_count(value: typeof get_subscriber_count): void {
|
||||
get_subscriber_count = value;
|
||||
}
|
||||
|
||||
export function get_subscribers(stream_id: number): number[] {
|
||||
|
|
|
@ -89,10 +89,14 @@ export function get_users_from_ids(user_ids: number[]): User[] {
|
|||
}
|
||||
|
||||
// Use this function only when you are sure that user_id is valid.
|
||||
export function get_by_user_id(user_id: number): User {
|
||||
export let get_by_user_id = (user_id: number): User => {
|
||||
const person = people_by_user_id_dict.get(user_id);
|
||||
assert(person, `Unknown user_id in get_by_user_id: ${user_id}`);
|
||||
return person;
|
||||
};
|
||||
|
||||
export function rewire_get_by_user_id(value: typeof get_by_user_id): void {
|
||||
get_by_user_id = value;
|
||||
}
|
||||
|
||||
// This is type unsafe version of get_by_user_id for the callers that expects undefined values.
|
||||
|
@ -123,7 +127,7 @@ export function validate_user_ids(user_ids: number[]): number[] {
|
|||
return good_ids;
|
||||
}
|
||||
|
||||
export function get_by_email(email: string): User | undefined {
|
||||
export let get_by_email = (email: string): User | undefined => {
|
||||
const person = people_dict.get(email);
|
||||
|
||||
if (!person) {
|
||||
|
@ -137,6 +141,10 @@ export function get_by_email(email: string): User | undefined {
|
|||
}
|
||||
|
||||
return person;
|
||||
};
|
||||
|
||||
export function rewire_get_by_email(value: typeof get_by_email): void {
|
||||
get_by_email = value;
|
||||
}
|
||||
|
||||
export function get_bot_owner_user(user: User & {is_bot: true}): User | undefined {
|
||||
|
@ -382,7 +390,7 @@ export function emails_strings_to_user_ids_string(emails_string: string): string
|
|||
return email_list_to_user_ids_string(emails);
|
||||
}
|
||||
|
||||
export function email_list_to_user_ids_string(emails: string[]): string | undefined {
|
||||
export let email_list_to_user_ids_string = (emails: string[]): string | undefined => {
|
||||
let user_ids = util.try_parse_as_truthy(
|
||||
emails.map((email) => {
|
||||
const person = get_by_email(email);
|
||||
|
@ -398,6 +406,12 @@ export function email_list_to_user_ids_string(emails: string[]): string | undefi
|
|||
user_ids = sort_numerically(user_ids);
|
||||
|
||||
return user_ids.join(",");
|
||||
};
|
||||
|
||||
export function rewire_email_list_to_user_ids_string(
|
||||
value: typeof email_list_to_user_ids_string,
|
||||
): void {
|
||||
email_list_to_user_ids_string = value;
|
||||
}
|
||||
|
||||
export function get_full_names_for_poll_option(user_ids: number[]): string {
|
||||
|
@ -1056,7 +1070,7 @@ export function get_bot_ids(): number[] {
|
|||
return bot_ids;
|
||||
}
|
||||
|
||||
export function get_active_human_count(): number {
|
||||
export let get_active_human_count = (): number => {
|
||||
let count = 0;
|
||||
for (const person of active_user_dict.values()) {
|
||||
if (!person.is_bot) {
|
||||
|
@ -1064,6 +1078,10 @@ export function get_active_human_count(): number {
|
|||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
export function rewire_get_active_human_count(value: typeof get_active_human_count): void {
|
||||
get_active_human_count = value;
|
||||
}
|
||||
|
||||
export function get_active_user_ids(): number[] {
|
||||
|
|
|
@ -11,8 +11,12 @@ type PMConversation = {
|
|||
|
||||
const partners = new Set<number>();
|
||||
|
||||
export function set_partner(user_id: number): void {
|
||||
export let set_partner = (user_id: number): void => {
|
||||
partners.add(user_id);
|
||||
};
|
||||
|
||||
export function rewire_set_partner(value: typeof set_partner): void {
|
||||
set_partner = value;
|
||||
}
|
||||
|
||||
export function is_partner(user_id: number): boolean {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import generated_pygments_data from "../generated/pygments_data.json";
|
||||
|
||||
type PygmentsLanguage = {priority: number; pretty_name: string};
|
||||
const langs: Record<string, PygmentsLanguage | undefined> = generated_pygments_data.langs;
|
||||
export let langs: Record<string, PygmentsLanguage | undefined> = generated_pygments_data.langs;
|
||||
|
||||
export {langs};
|
||||
export function rewire_langs(value: typeof langs): void {
|
||||
langs = value;
|
||||
}
|
||||
|
|
|
@ -249,10 +249,14 @@ export function get_reaction_sections(message_id: number): JQuery {
|
|||
return $rows.find(".message_reactions");
|
||||
}
|
||||
|
||||
export function find_reaction(message_id: number, local_id: string): JQuery {
|
||||
export let find_reaction = (message_id: number, local_id: string): JQuery => {
|
||||
const $reaction_section = get_reaction_sections(message_id);
|
||||
const $reaction = $reaction_section.find(`[data-reaction-id='${CSS.escape(local_id)}']`);
|
||||
return $reaction;
|
||||
};
|
||||
|
||||
export function rewire_find_reaction(value: typeof find_reaction): void {
|
||||
find_reaction = value;
|
||||
}
|
||||
|
||||
export function get_add_reaction_button(message_id: number): JQuery {
|
||||
|
@ -261,12 +265,16 @@ export function get_add_reaction_button(message_id: number): JQuery {
|
|||
return $add_button;
|
||||
}
|
||||
|
||||
export function set_reaction_vote_text($reaction: JQuery, vote_text: string): void {
|
||||
export let set_reaction_vote_text = ($reaction: JQuery, vote_text: string): void => {
|
||||
const $count_element = $reaction.find(".message_reaction_count");
|
||||
$count_element.text(vote_text);
|
||||
};
|
||||
|
||||
export function rewire_set_reaction_vote_text(value: typeof set_reaction_vote_text): void {
|
||||
set_reaction_vote_text = value;
|
||||
}
|
||||
|
||||
export function add_reaction(event: ReactionEvent): void {
|
||||
export let add_reaction = (event: ReactionEvent): void => {
|
||||
const message_id = event.message_id;
|
||||
const message = message_store.get(message_id);
|
||||
|
||||
|
@ -311,13 +319,17 @@ export function add_reaction(event: ReactionEvent): void {
|
|||
message.clean_reactions.set(local_id, clean_reaction_object);
|
||||
insert_new_reaction(clean_reaction_object, message, user_id);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_add_reaction(value: typeof add_reaction): void {
|
||||
add_reaction = value;
|
||||
}
|
||||
|
||||
export function update_existing_reaction(
|
||||
export let update_existing_reaction = (
|
||||
clean_reaction_object: MessageCleanReaction,
|
||||
message: Message,
|
||||
acting_user_id: number,
|
||||
): void {
|
||||
): void => {
|
||||
// Our caller ensures that this message already has a reaction
|
||||
// for this emoji and sets up our user_list. This function
|
||||
// simply updates the DOM.
|
||||
|
@ -335,13 +347,17 @@ export function update_existing_reaction(
|
|||
}
|
||||
|
||||
update_vote_text_on_message(message);
|
||||
};
|
||||
|
||||
export function rewire_update_existing_reaction(value: typeof update_existing_reaction): void {
|
||||
update_existing_reaction = value;
|
||||
}
|
||||
|
||||
export function insert_new_reaction(
|
||||
export let insert_new_reaction = (
|
||||
clean_reaction_object: MessageCleanReaction,
|
||||
message: Message,
|
||||
user_id: number,
|
||||
): void {
|
||||
): void => {
|
||||
// Our caller ensures we are the first user to react to this
|
||||
// message with this emoji. We then render the emoji/title/count
|
||||
// and insert it before the add button.
|
||||
|
@ -389,9 +405,13 @@ export function insert_new_reaction(
|
|||
}
|
||||
|
||||
update_vote_text_on_message(message);
|
||||
};
|
||||
|
||||
export function rewire_insert_new_reaction(value: typeof insert_new_reaction): void {
|
||||
insert_new_reaction = value;
|
||||
}
|
||||
|
||||
export function remove_reaction(event: ReactionEvent): void {
|
||||
export let remove_reaction = (event: ReactionEvent): void => {
|
||||
const message_id = event.message_id;
|
||||
const user_id = event.user_id;
|
||||
const message = message_store.get(message_id);
|
||||
|
@ -426,13 +446,17 @@ export function remove_reaction(event: ReactionEvent): void {
|
|||
update_user_fields(clean_reaction_object, should_display_reactors);
|
||||
|
||||
remove_reaction_from_view(clean_reaction_object, message, user_id);
|
||||
};
|
||||
|
||||
export function rewire_remove_reaction(value: typeof remove_reaction): void {
|
||||
remove_reaction = value;
|
||||
}
|
||||
|
||||
export function remove_reaction_from_view(
|
||||
export let remove_reaction_from_view = (
|
||||
clean_reaction_object: MessageCleanReaction,
|
||||
message: Message,
|
||||
user_id: number,
|
||||
): void {
|
||||
): void => {
|
||||
const local_id = get_local_reaction_id(clean_reaction_object);
|
||||
const $reaction = find_reaction(message.id, local_id);
|
||||
const reaction_count = clean_reaction_object.user_ids.length;
|
||||
|
@ -466,6 +490,10 @@ export function remove_reaction_from_view(
|
|||
}
|
||||
|
||||
update_vote_text_on_message(message);
|
||||
};
|
||||
|
||||
export function rewire_remove_reaction_from_view(value: typeof remove_reaction_from_view): void {
|
||||
remove_reaction_from_view = value;
|
||||
}
|
||||
|
||||
export function get_emojis_used_by_user_for_message_id(message_id: number): string[] {
|
||||
|
@ -687,7 +715,7 @@ function comma_separated_usernames(user_list: number[]): string {
|
|||
return comma_separated_usernames;
|
||||
}
|
||||
|
||||
export function update_vote_text_on_message(message: Message): void {
|
||||
export let update_vote_text_on_message = (message: Message): void => {
|
||||
// Because whether we display a count or the names of reacting
|
||||
// users depends on total reactions on the message, we need to
|
||||
// recalculate this whenever adjusting reaction rendering on a
|
||||
|
@ -703,4 +731,10 @@ export function update_vote_text_on_message(message: Message): void {
|
|||
message_clean_reaction.vote_text = vote_text;
|
||||
set_reaction_vote_text(reaction_elem, vote_text);
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_update_vote_text_on_message(
|
||||
value: typeof update_vote_text_on_message,
|
||||
): void {
|
||||
update_vote_text_on_message = value;
|
||||
}
|
||||
|
|
|
@ -930,7 +930,7 @@ export function bulk_inplace_rerender(row_keys: string[]): void {
|
|||
setTimeout(revive_current_focus, 0);
|
||||
}
|
||||
|
||||
export function inplace_rerender(topic_key: string, is_bulk_rerender?: boolean): boolean {
|
||||
export let inplace_rerender = (topic_key: string, is_bulk_rerender?: boolean): boolean => {
|
||||
if (!recent_view_util.is_visible()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -990,6 +990,10 @@ export function inplace_rerender(topic_key: string, is_bulk_rerender?: boolean):
|
|||
setTimeout(revive_current_focus, 0);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export function rewire_inplace_rerender(value: typeof inplace_rerender): void {
|
||||
inplace_rerender = value;
|
||||
}
|
||||
|
||||
export function update_topic_visibility_policy(stream_id: number, topic: string): boolean {
|
||||
|
|
|
@ -17,6 +17,11 @@ import * as util from "./util";
|
|||
|
||||
// Exported for unit testing
|
||||
export let is_using_input_method = false;
|
||||
|
||||
export function rewire_is_using_input_method(value: typeof is_using_input_method): void {
|
||||
is_using_input_method = value;
|
||||
}
|
||||
|
||||
export let search_pill_widget: SearchPillWidget | null = null;
|
||||
let search_input_has_changed = false;
|
||||
|
||||
|
@ -390,7 +395,7 @@ function reset_searchbox(clear = false): void {
|
|||
}
|
||||
|
||||
// Exported for tests
|
||||
export function exit_search(opts: {keep_search_narrow_open: boolean}): void {
|
||||
export let exit_search = (opts: {keep_search_narrow_open: boolean}): void => {
|
||||
const filter = narrow_state.filter();
|
||||
if (!filter || filter.is_common_narrow()) {
|
||||
// for common narrows, we change the UI (and don't redirect)
|
||||
|
@ -404,13 +409,23 @@ export function exit_search(opts: {keep_search_narrow_open: boolean}): void {
|
|||
}
|
||||
$("#search_query").trigger("blur");
|
||||
$(".app").trigger("focus");
|
||||
};
|
||||
|
||||
export function rewire_exit_search(value: typeof exit_search): void {
|
||||
exit_search = value;
|
||||
}
|
||||
|
||||
export function open_search_bar_and_close_narrow_description(clear = false): void {
|
||||
export let open_search_bar_and_close_narrow_description = (clear = false): void => {
|
||||
reset_searchbox(clear);
|
||||
$(".navbar-search").addClass("expanded");
|
||||
$("#message_view_header").addClass("hidden");
|
||||
popovers.hide_all();
|
||||
};
|
||||
|
||||
export function rewire_open_search_bar_and_close_narrow_description(
|
||||
value: typeof open_search_bar_and_close_narrow_description,
|
||||
): void {
|
||||
open_search_bar_and_close_narrow_description = value;
|
||||
}
|
||||
|
||||
export function close_search_bar_and_open_narrow_description(): void {
|
||||
|
|
|
@ -631,10 +631,10 @@ export function get_input_type($input_elem: JQuery, input_type?: string): string
|
|||
return input_type;
|
||||
}
|
||||
|
||||
export function get_input_element_value(
|
||||
export let get_input_element_value = (
|
||||
input_elem: HTMLElement,
|
||||
input_type?: string,
|
||||
): boolean | number | string | null | undefined | GroupSettingValue {
|
||||
): boolean | number | string | null | undefined | GroupSettingValue => {
|
||||
const $input_elem = $(input_elem);
|
||||
input_type = get_input_type($input_elem, input_type);
|
||||
let input_value;
|
||||
|
@ -691,6 +691,10 @@ export function get_input_element_value(
|
|||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_get_input_element_value(value: typeof get_input_element_value): void {
|
||||
get_input_element_value = value;
|
||||
}
|
||||
|
||||
export function set_input_element_value(
|
||||
|
|
|
@ -899,7 +899,7 @@ export function set_up_dropdown_widget_for_realm_group_settings(): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function init_dropdown_widgets(): void {
|
||||
export let init_dropdown_widgets = (): void => {
|
||||
const notification_stream_options = (): dropdown_widget.Option[] => {
|
||||
const streams = stream_settings_data.get_streams_for_settings_page();
|
||||
const options: dropdown_widget.Option[] = streams.map((stream) => ({
|
||||
|
@ -956,6 +956,10 @@ export function init_dropdown_widgets(): void {
|
|||
);
|
||||
|
||||
set_up_dropdown_widget_for_realm_group_settings();
|
||||
};
|
||||
|
||||
export function rewire_init_dropdown_widgets(value: typeof init_dropdown_widgets): void {
|
||||
init_dropdown_widgets = value;
|
||||
}
|
||||
|
||||
export function register_save_discard_widget_handlers(
|
||||
|
@ -1055,7 +1059,7 @@ export function register_save_discard_widget_handlers(
|
|||
}
|
||||
|
||||
// Exported for tests
|
||||
export function initialize_group_setting_widgets(): void {
|
||||
export let initialize_group_setting_widgets = (): void => {
|
||||
const realm_group_permission_settings = Object.entries(
|
||||
realm.server_supported_permission_settings.realm,
|
||||
);
|
||||
|
@ -1080,6 +1084,12 @@ export function initialize_group_setting_widgets(): void {
|
|||
|
||||
enable_or_disable_group_permission_settings();
|
||||
check_disable_direct_message_initiator_group_widget();
|
||||
};
|
||||
|
||||
export function rewire_initialize_group_setting_widgets(
|
||||
value: typeof initialize_group_setting_widgets,
|
||||
): void {
|
||||
initialize_group_setting_widgets = value;
|
||||
}
|
||||
|
||||
export function build_page(): void {
|
||||
|
|
|
@ -217,7 +217,7 @@ export function get_stream_name_from_id(stream_id: number): string {
|
|||
return get_sub_by_id(stream_id)?.name ?? "";
|
||||
}
|
||||
|
||||
export function get_sub_by_name(name: string): StreamSubscription | undefined {
|
||||
export let get_sub_by_name = (name: string): StreamSubscription | undefined => {
|
||||
// Note: Only use this function for situations where
|
||||
// you are comfortable with a user dealing with an
|
||||
// old name of a stream (from prior to a rename).
|
||||
|
@ -230,6 +230,10 @@ export function get_sub_by_name(name: string): StreamSubscription | undefined {
|
|||
}
|
||||
|
||||
return sub_store.get(stream_id);
|
||||
};
|
||||
|
||||
export function rewire_get_sub_by_name(value: typeof get_sub_by_name): void {
|
||||
get_sub_by_name = value;
|
||||
}
|
||||
|
||||
export function id_to_slug(stream_id: number): string {
|
||||
|
@ -449,7 +453,7 @@ export function canonicalized_name(stream_name: string): string {
|
|||
return stream_name.toString().toLowerCase();
|
||||
}
|
||||
|
||||
export function get_color(stream_id: number | undefined): string {
|
||||
export let get_color = (stream_id: number | undefined): string => {
|
||||
if (stream_id === undefined) {
|
||||
return DEFAULT_COLOR;
|
||||
}
|
||||
|
@ -458,6 +462,10 @@ export function get_color(stream_id: number | undefined): string {
|
|||
return DEFAULT_COLOR;
|
||||
}
|
||||
return sub.color;
|
||||
};
|
||||
|
||||
export function rewire_get_color(value: typeof get_color): void {
|
||||
get_color = value;
|
||||
}
|
||||
|
||||
export function is_muted(stream_id: number): boolean {
|
||||
|
@ -675,7 +683,7 @@ export function is_default_stream_id(stream_id: number): boolean {
|
|||
return default_stream_ids.has(stream_id);
|
||||
}
|
||||
|
||||
export function is_user_subscribed(stream_id: number, user_id: number): boolean {
|
||||
export let is_user_subscribed = (stream_id: number, user_id: number): boolean => {
|
||||
const sub = sub_store.get(stream_id);
|
||||
if (sub === undefined || !can_view_subscribers(sub)) {
|
||||
// If we don't know about the stream, or we ourselves cannot access subscriber list,
|
||||
|
@ -691,6 +699,10 @@ export function is_user_subscribed(stream_id: number, user_id: number): boolean
|
|||
}
|
||||
|
||||
return peer_data.is_user_subscribed(stream_id, user_id);
|
||||
};
|
||||
|
||||
export function rewire_is_user_subscribed(value: typeof is_user_subscribed): void {
|
||||
is_user_subscribed = value;
|
||||
}
|
||||
|
||||
export function create_streams(streams: Stream[]): void {
|
||||
|
|
|
@ -41,6 +41,10 @@ let zoomed_in = false;
|
|||
|
||||
export let stream_cursor: ListCursor<number>;
|
||||
|
||||
export function rewire_stream_cursor(value: typeof stream_cursor): void {
|
||||
stream_cursor = value;
|
||||
}
|
||||
|
||||
let has_scrolled = false;
|
||||
|
||||
export function is_zoomed_in(): boolean {
|
||||
|
@ -97,13 +101,13 @@ export function clear_topics(): void {
|
|||
zoomed_in = false;
|
||||
}
|
||||
|
||||
export function update_count_in_dom(
|
||||
export let update_count_in_dom = (
|
||||
$stream_li: JQuery,
|
||||
stream_counts: StreamCountInfo,
|
||||
stream_has_any_unread_mention_messages: boolean,
|
||||
stream_has_any_unmuted_unread_mention: boolean,
|
||||
stream_has_only_muted_unread_mention: boolean,
|
||||
): void {
|
||||
): void => {
|
||||
// The subscription_block properly excludes the topic list,
|
||||
// and it also has sensitive margins related to whether the
|
||||
// count is there or not.
|
||||
|
@ -176,6 +180,10 @@ export function update_count_in_dom(
|
|||
$subscription_block.removeClass("has-only-muted-unreads");
|
||||
$subscription_block.removeClass("stream-with-count");
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_update_count_in_dom(value: typeof update_count_in_dom): void {
|
||||
update_count_in_dom = value;
|
||||
}
|
||||
|
||||
class StreamSidebar {
|
||||
|
@ -567,7 +575,7 @@ function set_stream_unread_count(
|
|||
);
|
||||
}
|
||||
|
||||
export function update_streams_sidebar(force_rerender = false): void {
|
||||
export let update_streams_sidebar = (force_rerender = false): void => {
|
||||
if (!force_rerender && is_zoomed_in()) {
|
||||
// We do our best to update topics that are displayed
|
||||
// in case user zoomed in. Streams list will be updated,
|
||||
|
@ -591,6 +599,10 @@ export function update_streams_sidebar(force_rerender = false): void {
|
|||
}
|
||||
|
||||
update_stream_sidebar_for_narrow(filter);
|
||||
};
|
||||
|
||||
export function rewire_update_streams_sidebar(value: typeof update_streams_sidebar): void {
|
||||
update_streams_sidebar = value;
|
||||
}
|
||||
|
||||
export function update_dom_with_unread_counts(counts: FullUnreadCountsData): void {
|
||||
|
|
|
@ -58,7 +58,7 @@ export function is_filtering_inactives(): boolean {
|
|||
return filter_out_inactives;
|
||||
}
|
||||
|
||||
export function has_recent_activity(sub: StreamSubscription): boolean {
|
||||
export let has_recent_activity = (sub: StreamSubscription): boolean => {
|
||||
if (!filter_out_inactives || sub.pin_to_top) {
|
||||
// If users don't want to filter inactive streams
|
||||
// to the bottom, we respect that setting and don't
|
||||
|
@ -70,6 +70,10 @@ export function has_recent_activity(sub: StreamSubscription): boolean {
|
|||
return true;
|
||||
}
|
||||
return stream_topic_history.stream_has_topics(sub.stream_id) || sub.newly_subscribed;
|
||||
};
|
||||
|
||||
export function rewire_has_recent_activity(value: typeof has_recent_activity): void {
|
||||
has_recent_activity = value;
|
||||
}
|
||||
|
||||
export function has_recent_activity_but_muted(sub: StreamSubscription): boolean {
|
||||
|
|
|
@ -356,10 +356,14 @@ export function has_history_for(stream_id: number): boolean {
|
|||
return fetched_stream_ids.has(stream_id);
|
||||
}
|
||||
|
||||
export function get_recent_topic_names(stream_id: number): string[] {
|
||||
export let get_recent_topic_names = (stream_id: number): string[] => {
|
||||
const history = find_or_create(stream_id);
|
||||
|
||||
return history.get_recent_topic_names();
|
||||
};
|
||||
|
||||
export function rewire_get_recent_topic_names(value: typeof get_recent_topic_names): void {
|
||||
get_recent_topic_names = value;
|
||||
}
|
||||
|
||||
export function get_max_message_id(stream_id: number): number {
|
||||
|
|
|
@ -33,8 +33,11 @@ export type StreamSubscription = z.infer<typeof stream_subscription_schema>;
|
|||
|
||||
const subs_by_stream_id = new Map<number, StreamSubscription>();
|
||||
|
||||
export function get(stream_id: number): StreamSubscription | undefined {
|
||||
return subs_by_stream_id.get(stream_id);
|
||||
export let get = (stream_id: number): StreamSubscription | undefined =>
|
||||
subs_by_stream_id.get(stream_id);
|
||||
|
||||
export function rewire_get(value: typeof get): void {
|
||||
get = value;
|
||||
}
|
||||
|
||||
export function validate_stream_ids(stream_ids: number[]): number[] {
|
||||
|
|
|
@ -175,7 +175,7 @@ export type TimeRender = {
|
|||
needs_update: boolean;
|
||||
};
|
||||
|
||||
export function render_now(time: Date, today = new Date(), display_year?: boolean): TimeRender {
|
||||
export let render_now = (time: Date, today = new Date(), display_year?: boolean): TimeRender => {
|
||||
let time_str = "";
|
||||
let needs_update = false;
|
||||
// render formal time to be used for tippy tooltip
|
||||
|
@ -210,6 +210,10 @@ export function render_now(time: Date, today = new Date(), display_year?: boolea
|
|||
formal_time_str,
|
||||
needs_update,
|
||||
};
|
||||
};
|
||||
|
||||
export function rewire_render_now(value: typeof render_now): void {
|
||||
render_now = value;
|
||||
}
|
||||
|
||||
// Relative time rendering for use in most screens like Recent conversations.
|
||||
|
|
|
@ -94,7 +94,7 @@ type StreamData = {
|
|||
subscribed: boolean;
|
||||
};
|
||||
|
||||
export function render_typeahead_item(args: {
|
||||
export let render_typeahead_item = (args: {
|
||||
primary?: string | undefined;
|
||||
is_person?: boolean;
|
||||
img_src?: string;
|
||||
|
@ -105,7 +105,7 @@ export function render_typeahead_item(args: {
|
|||
is_user_group?: boolean;
|
||||
stream?: StreamData;
|
||||
emoji_code?: string | undefined;
|
||||
}): string {
|
||||
}): string => {
|
||||
const has_image = args.img_src !== undefined;
|
||||
const has_status = args.status_emoji_info !== undefined;
|
||||
const has_secondary = args.secondary !== undefined;
|
||||
|
@ -119,9 +119,13 @@ export function render_typeahead_item(args: {
|
|||
has_secondary_html,
|
||||
has_pronouns,
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_render_typeahead_item(value: typeof render_typeahead_item): void {
|
||||
render_typeahead_item = value;
|
||||
}
|
||||
|
||||
export function render_person(person: UserPillData | UserOrMentionPillData): string {
|
||||
export let render_person = (person: UserPillData | UserOrMentionPillData): string => {
|
||||
if (person.type === "broadcast") {
|
||||
return render_typeahead_item({
|
||||
primary: person.user.special_item_text,
|
||||
|
@ -155,14 +159,21 @@ export function render_person(person: UserPillData | UserOrMentionPillData): str
|
|||
};
|
||||
|
||||
return render_typeahead_item(typeahead_arguments);
|
||||
};
|
||||
|
||||
export function rewire_render_person(value: typeof render_person): void {
|
||||
render_person = value;
|
||||
}
|
||||
|
||||
export function render_user_group(user_group: {name: string; description: string}): string {
|
||||
return render_typeahead_item({
|
||||
export let render_user_group = (user_group: {name: string; description: string}): string =>
|
||||
render_typeahead_item({
|
||||
primary: user_groups.get_display_group_name(user_group.name),
|
||||
secondary: user_group.description,
|
||||
is_user_group: true,
|
||||
});
|
||||
|
||||
export function rewire_render_user_group(value: typeof render_user_group): void {
|
||||
render_user_group = value;
|
||||
}
|
||||
|
||||
export function render_person_or_user_group(
|
||||
|
@ -175,14 +186,17 @@ export function render_person_or_user_group(
|
|||
return render_person(item);
|
||||
}
|
||||
|
||||
export function render_stream(stream: StreamData): string {
|
||||
return render_typeahead_item({
|
||||
export let render_stream = (stream: StreamData): string =>
|
||||
render_typeahead_item({
|
||||
secondary_html: stream.rendered_description,
|
||||
stream,
|
||||
});
|
||||
|
||||
export function rewire_render_stream(value: typeof render_stream): void {
|
||||
render_stream = value;
|
||||
}
|
||||
|
||||
export function render_emoji(item: EmojiSuggestion): string {
|
||||
export let render_emoji = (item: EmojiSuggestion): string => {
|
||||
const args = {
|
||||
is_emoji: true,
|
||||
primary: item.emoji_name.replaceAll("_", " "),
|
||||
|
@ -198,6 +212,10 @@ export function render_emoji(item: EmojiSuggestion): string {
|
|||
...args,
|
||||
emoji_code: item.emoji_code,
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_render_emoji(value: typeof render_emoji): void {
|
||||
render_emoji = value;
|
||||
}
|
||||
|
||||
export function sorter<T>(query: string, objs: T[], get_item: (x: T) => string): T[] {
|
||||
|
@ -415,7 +433,7 @@ export function sort_languages(matches: LanguageSuggestion[], query: string): La
|
|||
}));
|
||||
}
|
||||
|
||||
export function sort_recipients<UserType extends UserOrMentionPillData | UserPillData>({
|
||||
export let sort_recipients = <UserType extends UserOrMentionPillData | UserPillData>({
|
||||
users,
|
||||
query,
|
||||
current_stream_id,
|
||||
|
@ -429,7 +447,7 @@ export function sort_recipients<UserType extends UserOrMentionPillData | UserPil
|
|||
current_topic?: string | undefined;
|
||||
groups?: UserGroupPillData[];
|
||||
max_num_items?: number | undefined;
|
||||
}): (UserType | UserGroupPillData)[] {
|
||||
}): (UserType | UserGroupPillData)[] => {
|
||||
function sort_relevance(items: UserType[]): UserType[] {
|
||||
return sort_people_for_relevance(items, current_stream_id, current_topic);
|
||||
}
|
||||
|
@ -556,6 +574,10 @@ export function sort_recipients<UserType extends UserOrMentionPillData | UserPil
|
|||
// FirstName, which we don't want to artificially prioritize over the
|
||||
// the lone active user whose name is FirstName LastName.
|
||||
return recipients.slice(0, max_num_items);
|
||||
};
|
||||
|
||||
export function rewire_sort_recipients(value: typeof sort_recipients): void {
|
||||
sort_recipients = value;
|
||||
}
|
||||
|
||||
export function compare_setting_options(
|
||||
|
@ -618,7 +640,7 @@ export function compare_setting_options(
|
|||
return 1;
|
||||
}
|
||||
|
||||
export function sort_group_setting_options({
|
||||
export let sort_group_setting_options = ({
|
||||
users,
|
||||
query,
|
||||
groups,
|
||||
|
@ -628,7 +650,7 @@ export function sort_group_setting_options({
|
|||
query: string;
|
||||
groups: UserGroupPillData[];
|
||||
target_group: UserGroup | undefined;
|
||||
}): (UserPillData | UserGroupPillData)[] {
|
||||
}): (UserPillData | UserGroupPillData)[] => {
|
||||
function sort_group_setting_items(
|
||||
objs: (UserPillData | UserGroupPillData)[],
|
||||
): (UserPillData | UserGroupPillData)[] {
|
||||
|
@ -703,6 +725,10 @@ export function sort_group_setting_options({
|
|||
}
|
||||
|
||||
return setting_options.slice(0, MAX_ITEMS);
|
||||
};
|
||||
|
||||
export function rewire_sort_group_setting_options(value: typeof sort_group_setting_options): void {
|
||||
sort_group_setting_options = value;
|
||||
}
|
||||
|
||||
type SlashCommand = {
|
||||
|
@ -781,7 +807,7 @@ function compare_by_name(stream_a: StreamSubscription, stream_b: StreamSubscript
|
|||
return util.strcmp(stream_a.name, stream_b.name);
|
||||
}
|
||||
|
||||
export function sort_streams(matches: StreamPillData[], query: string): StreamPillData[] {
|
||||
export let sort_streams = (matches: StreamPillData[], query: string): StreamPillData[] => {
|
||||
const name_results = typeahead.triage(query, matches, (x) => x.name, compare_by_activity);
|
||||
const desc_results = typeahead.triage(
|
||||
query,
|
||||
|
@ -791,11 +817,19 @@ export function sort_streams(matches: StreamPillData[], query: string): StreamPi
|
|||
);
|
||||
|
||||
return [...name_results.matches, ...desc_results.matches, ...desc_results.rest];
|
||||
};
|
||||
|
||||
export function rewire_sort_streams(value: typeof sort_streams): void {
|
||||
sort_streams = value;
|
||||
}
|
||||
|
||||
export function sort_streams_by_name(matches: StreamPillData[], query: string): StreamPillData[] {
|
||||
export let sort_streams_by_name = (matches: StreamPillData[], query: string): StreamPillData[] => {
|
||||
const results = typeahead.triage(query, matches, (x) => x.name, compare_by_name);
|
||||
return [...results.matches, ...results.rest];
|
||||
};
|
||||
|
||||
export function rewire_sort_streams_by_name(value: typeof sort_streams_by_name): void {
|
||||
sort_streams_by_name = value;
|
||||
}
|
||||
|
||||
export function query_matches_person(
|
||||
|
|
|
@ -72,10 +72,15 @@ export function is_user_said_paragraph($element: JQuery): boolean {
|
|||
return remaining_text.trim() === ":";
|
||||
}
|
||||
|
||||
export function get_collapsible_status_array($elements: JQuery): boolean[] {
|
||||
return [...$elements].map(
|
||||
export let get_collapsible_status_array = ($elements: JQuery): boolean[] =>
|
||||
[...$elements].map(
|
||||
(element) => $(element).is("blockquote") || is_user_said_paragraph($(element)),
|
||||
);
|
||||
|
||||
export function rewire_get_collapsible_status_array(
|
||||
value: typeof get_collapsible_status_array,
|
||||
): void {
|
||||
get_collapsible_status_array = value;
|
||||
}
|
||||
|
||||
export function potentially_collapse_quotes($element: JQuery): boolean {
|
||||
|
|
|
@ -125,7 +125,7 @@ export function edit_config(row: number): Config {
|
|||
};
|
||||
}
|
||||
|
||||
export function hide_upload_banner(uppy: Uppy, config: Config, file_id: string): void {
|
||||
export let hide_upload_banner = (uppy: Uppy, config: Config, file_id: string): void => {
|
||||
config.upload_banner(file_id).remove();
|
||||
if (uppy.getFiles().length === 0) {
|
||||
if (config.mode === "compose") {
|
||||
|
@ -134,6 +134,10 @@ export function hide_upload_banner(uppy: Uppy, config: Config, file_id: string):
|
|||
config.send_button().prop("disabled", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_hide_upload_banner(value: typeof hide_upload_banner): void {
|
||||
hide_upload_banner = value;
|
||||
}
|
||||
|
||||
function add_upload_banner(
|
||||
|
@ -172,7 +176,7 @@ export function show_error_message(
|
|||
}
|
||||
}
|
||||
|
||||
export function upload_files(uppy: Uppy, config: Config, files: File[] | FileList): void {
|
||||
export let upload_files = (uppy: Uppy, config: Config, files: File[] | FileList): void => {
|
||||
if (files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,6 +234,7 @@ export function upload_files(uppy: Uppy, config: Config, files: File[] | FileLis
|
|||
file_id,
|
||||
true,
|
||||
);
|
||||
// eslint-disable-next-line no-loop-func
|
||||
config.upload_banner_cancel_button(file_id).one("click", () => {
|
||||
compose_ui.replace_syntax(get_translated_status(file), "", config.textarea());
|
||||
compose_ui.autosize_textarea(config.textarea());
|
||||
|
@ -238,10 +243,15 @@ export function upload_files(uppy: Uppy, config: Config, files: File[] | FileLis
|
|||
uppy.removeFile(file_id);
|
||||
hide_upload_banner(uppy, config, file_id);
|
||||
});
|
||||
// eslint-disable-next-line no-loop-func
|
||||
config.upload_banner_hide_button(file_id).one("click", () => {
|
||||
hide_upload_banner(uppy, config, file_id);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function rewire_upload_files(value: typeof upload_files): void {
|
||||
upload_files = value;
|
||||
}
|
||||
|
||||
export function setup_upload(config: Config): Uppy {
|
||||
|
|
|
@ -116,7 +116,7 @@ export function get_user_topics_for_visibility_policy(visibility_policy: number)
|
|||
return topics;
|
||||
}
|
||||
|
||||
export function set_user_topic_visibility_policy(
|
||||
export let set_user_topic_visibility_policy = (
|
||||
stream_id: number,
|
||||
topic: string,
|
||||
visibility_policy: number,
|
||||
|
@ -125,7 +125,7 @@ export function set_user_topic_visibility_policy(
|
|||
$status_element?: JQuery,
|
||||
success_cb?: () => void,
|
||||
error_cb?: () => void,
|
||||
): void {
|
||||
): void => {
|
||||
const data = {
|
||||
stream_id,
|
||||
topic,
|
||||
|
@ -203,6 +203,12 @@ export function set_user_topic_visibility_policy(
|
|||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export function rewire_set_user_topic_visibility_policy(
|
||||
value: typeof set_user_topic_visibility_policy,
|
||||
): void {
|
||||
set_user_topic_visibility_policy = value;
|
||||
}
|
||||
|
||||
export function set_visibility_policy_for_element($elt: JQuery, visibility_policy: number): void {
|
||||
|
|
|
@ -315,7 +315,7 @@ export function get_time_from_date_muted(date_muted: number | undefined): number
|
|||
return date_muted * 1000;
|
||||
}
|
||||
|
||||
export function call_function_periodically(callback: () => void, delay: number): void {
|
||||
export let call_function_periodically = (callback: () => void, delay: number): void => {
|
||||
// We previously used setInterval for this purpose, but
|
||||
// empirically observed that after unsuspend, Chrome can end
|
||||
// up trying to "catch up" by doing dozens of these requests
|
||||
|
@ -337,6 +337,10 @@ export function call_function_periodically(callback: () => void, delay: number):
|
|||
// exception.
|
||||
callback();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
export function rewire_call_function_periodically(value: typeof call_function_periodically): void {
|
||||
call_function_periodically = value;
|
||||
}
|
||||
|
||||
export function get_string_diff(string1: string, string2: string): [number, number, number] {
|
||||
|
|
Loading…
Reference in New Issue