diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 1848796b2b..00209fd366 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -226,6 +226,7 @@ EXEMPT_FILES = make_set( "web/src/stream_muting.js", "web/src/stream_popover.js", "web/src/stream_settings_api.js", + "web/src/stream_settings_components.js", "web/src/stream_settings_containers.ts", "web/src/stream_settings_ui.js", "web/src/stream_ui_updates.js", diff --git a/web/src/compose_setup.js b/web/src/compose_setup.js index 89a466c285..30986ba967 100644 --- a/web/src/compose_setup.js +++ b/web/src/compose_setup.js @@ -18,7 +18,7 @@ import * as rows from "./rows"; import * as scheduled_messages from "./scheduled_messages"; import * as scheduled_messages_popover from "./scheduled_messages_popover"; import * as stream_data from "./stream_data"; -import * as stream_settings_ui from "./stream_settings_ui"; +import * as stream_settings_components from "./stream_settings_components"; import * as sub_store from "./sub_store"; import * as subscriber_api from "./subscriber_api"; import {get_timestamp_for_flatpickr} from "./timerender"; @@ -134,7 +134,7 @@ export function initialize() { return; } const sub = stream_data.get_sub_by_id(stream_id); - stream_settings_ui.sub_or_unsub(sub); + stream_settings_components.sub_or_unsub(sub); $(user_not_subscribed_selector).remove(); }, ); diff --git a/web/src/stream_create.js b/web/src/stream_create.js index af349b6b05..a3af22fe84 100644 --- a/web/src/stream_create.js +++ b/web/src/stream_create.js @@ -14,7 +14,7 @@ import * as people from "./people"; import * as settings_data from "./settings_data"; import * as stream_create_subscribers from "./stream_create_subscribers"; import * as stream_data from "./stream_data"; -import * as stream_settings_ui from "./stream_settings_ui"; +import * as stream_settings_components from "./stream_settings_components"; import * as stream_ui_updates from "./stream_ui_updates"; import * as ui_report from "./ui_report"; import {parse_html} from "./ui_util"; @@ -259,7 +259,7 @@ function create_stream() { data.principals = JSON.stringify(user_ids); const can_remove_subscribers_group_id = Number.parseInt( - stream_settings_ui.new_stream_can_remove_subscribers_group_widget.value(), + stream_settings_components.new_stream_can_remove_subscribers_group_widget.value(), 10, ); data.can_remove_subscribers_group = can_remove_subscribers_group_id; @@ -309,7 +309,7 @@ function create_stream() { export function new_stream_clicked(stream_name) { // this changes the tab switcher (settings/preview) which isn't necessary // to a add new stream title. - stream_settings_ui.show_subs_pane.create_stream(); + stream_settings_components.show_subs_pane.create_stream(); $(".stream-row.active").removeClass("active"); if (stream_name !== "") { @@ -328,7 +328,9 @@ function clear_error_display() { export function show_new_stream_modal() { $("#stream-creation").removeClass("hide"); $(".right .settings").hide(); - stream_settings_ui.hide_or_disable_stream_privacy_options_if_required($("#stream-creation")); + stream_settings_components.hide_or_disable_stream_privacy_options_if_required( + $("#stream-creation"), + ); stream_create_subscribers.build_widgets(); @@ -458,5 +460,5 @@ export function set_up_handlers() { } }); - stream_settings_ui.new_stream_can_remove_subscribers_group_widget.setup(); + stream_settings_components.new_stream_can_remove_subscribers_group_widget.setup(); } diff --git a/web/src/stream_edit.js b/web/src/stream_edit.js index c511657742..88f36c5d6b 100644 --- a/web/src/stream_edit.js +++ b/web/src/stream_edit.js @@ -29,9 +29,9 @@ import * as stream_data from "./stream_data"; import * as stream_edit_subscribers from "./stream_edit_subscribers"; import * as stream_edit_toggler from "./stream_edit_toggler"; import * as stream_settings_api from "./stream_settings_api"; +import * as stream_settings_components from "./stream_settings_components"; import * as stream_settings_containers from "./stream_settings_containers"; import * as stream_settings_data from "./stream_settings_data"; -import * as stream_settings_ui from "./stream_settings_ui"; import * as stream_ui_updates from "./stream_ui_updates"; import * as sub_store from "./sub_store"; import * as ui_report from "./ui_report"; @@ -94,17 +94,17 @@ export function open_edit_panel_for_row(stream_row) { const sub = get_sub_for_target(stream_row); $(".stream-row.active").removeClass("active"); - stream_settings_ui.show_subs_pane.settings(sub); + stream_settings_components.show_subs_pane.settings(sub); $(stream_row).addClass("active"); setup_subscriptions_stream_hash(sub); setup_stream_settings(stream_row); } export function open_edit_panel_empty() { - const tab_key = stream_settings_ui.get_active_data().$tabs.first().attr("data-tab-key"); + const tab_key = stream_settings_components.get_active_data().$tabs.first().attr("data-tab-key"); $(".stream-row.active").removeClass("active"); $("#subscription_overlay .right").removeClass("show"); - stream_settings_ui.show_subs_pane.nothing_selected(); + stream_settings_components.show_subs_pane.nothing_selected(); setup_subscriptions_tab_hash(tab_key); } @@ -113,9 +113,9 @@ export function update_stream_name(sub, new_name) { $edit_container.find(".email-address").text(sub.email_address); $edit_container.find(".sub-stream-name").text(new_name); - const active_data = stream_settings_ui.get_active_data(); + const active_data = stream_settings_components.get_active_data(); if (active_data.id === sub.stream_id) { - stream_settings_ui.set_right_panel_title(sub); + stream_settings_components.set_right_panel_title(sub); } } @@ -358,7 +358,7 @@ export function initialize() { return; } - stream_settings_ui.sub_or_unsub(sub); + stream_settings_components.sub_or_unsub(sub); }); $("#streams_overlay_container").on("click", "#open_stream_info_modal", (e) => { @@ -425,7 +425,7 @@ export function initialize() { )}']`, ); const sub = sub_store.get(stream_id); - stream_settings_ui.sub_or_unsub(sub, $stream_row); + stream_settings_components.sub_or_unsub(sub, $stream_row); $("#stream_permission_settings .stream-permissions-warning-banner").empty(); }, ); @@ -542,7 +542,7 @@ export function initialize() { sub.stream_id, )}']`, ); - stream_settings_ui.sub_or_unsub(sub, $stream_row); + stream_settings_components.sub_or_unsub(sub, $stream_row); if (!sub.subscribed) { open_edit_panel_for_row($stream_row); diff --git a/web/src/stream_popover.js b/web/src/stream_popover.js index 139d14baac..9cb70715e4 100644 --- a/web/src/stream_popover.js +++ b/web/src/stream_popover.js @@ -21,6 +21,7 @@ import * as stream_bar from "./stream_bar"; import * as stream_color from "./stream_color"; import * as stream_data from "./stream_data"; import * as stream_settings_api from "./stream_settings_api"; +import * as stream_settings_components from "./stream_settings_components"; import * as stream_settings_ui from "./stream_settings_ui"; import * as sub_store from "./sub_store"; import * as ui_report from "./ui_report"; @@ -177,7 +178,7 @@ function build_stream_popover(opts) { $(this).closest(".popover").fadeOut(500).delay(500).remove(); const sub = stream_popover_sub(e); - stream_settings_ui.sub_or_unsub(sub); + stream_settings_components.sub_or_unsub(sub); e.preventDefault(); e.stopPropagation(); }); diff --git a/web/src/stream_settings_components.js b/web/src/stream_settings_components.js new file mode 100644 index 0000000000..5f384eae2c --- /dev/null +++ b/web/src/stream_settings_components.js @@ -0,0 +1,252 @@ +import $ from "jquery"; + +import render_unsubscribe_private_stream_modal from "../templates/confirm_dialog/confirm_unsubscribe_private_stream.hbs"; +import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs"; +import render_selected_stream_title from "../templates/stream_settings/selected_stream_title.hbs"; + +import * as channel from "./channel"; +import * as confirm_dialog from "./confirm_dialog"; +import * as dropdown_widget from "./dropdown_widget"; +import {$t, $t_html} from "./i18n"; +import * as loading from "./loading"; +import * as overlays from "./overlays"; +import {page_params} from "./page_params"; +import * as peer_data from "./peer_data"; +import * as people from "./people"; +import * as settings_config from "./settings_config"; +import * as settings_data from "./settings_data"; +import * as stream_ui_updates from "./stream_ui_updates"; +import * as ui_report from "./ui_report"; +import * as user_groups from "./user_groups"; + +export function set_right_panel_title(sub) { + let title_icon_color = "#333333"; + if (settings_data.using_dark_theme()) { + title_icon_color = "#dddeee"; + } + $("#subscription_overlay .stream-info-title").html( + render_selected_stream_title({sub, title_icon_color}), + ); +} + +export const show_subs_pane = { + nothing_selected() { + $(".settings, #stream-creation").hide(); + $(".nothing-selected").show(); + $("#subscription_overlay .stream-info-title").text($t({defaultMessage: "Stream settings"})); + }, + settings(sub) { + $(".settings, #stream-creation").hide(); + $(".settings").show(); + set_right_panel_title(sub); + }, + create_stream() { + $(".nothing-selected, .settings, #stream-creation").hide(); + $("#stream-creation").show(); + $("#subscription_overlay .stream-info-title").text($t({defaultMessage: "Create stream"})); + }, +}; + +export function get_active_data() { + const $active_row = $("div.stream-row.active"); + const valid_active_id = Number.parseInt($active_row.attr("data-stream-id"), 10); + const $active_tabs = $(".subscriptions-container").find("div.ind-tab.selected"); + return { + $row: $active_row, + id: valid_active_id, + $tabs: $active_tabs, + }; +} + +export let new_stream_can_remove_subscribers_group_widget = null; + +export function dropdown_setup() { + new_stream_can_remove_subscribers_group_widget = new dropdown_widget.DropdownWidget({ + widget_name: "new_stream_can_remove_subscribers_group", + get_options: () => + user_groups.get_realm_user_groups_for_dropdown_list_widget( + "can_remove_subscribers_group", + ), + item_click_callback(event, dropdown) { + dropdown.hide(); + event.preventDefault(); + event.stopPropagation(); + new_stream_can_remove_subscribers_group_widget.render(); + }, + $events_container: $("#subscription_overlay"), + tippy_props: { + placement: "bottom-start", + }, + on_mount_callback(dropdown) { + $(dropdown.popper).css("min-width", "300px"); + }, + default_text: $t({defaultMessage: "No user groups"}), + default_id: user_groups.get_user_group_from_name("role:administrators").id, + unique_id_type: dropdown_widget.DATA_TYPES.NUMBER, + }); +} + +/* For the given stream_row, remove the tick and replace by a spinner. */ +function display_subscribe_toggle_spinner(stream_row) { + /* Prevent sending multiple requests by removing the button class. */ + $(stream_row).find(".check").removeClass("sub_unsub_button"); + + /* Hide the tick. */ + const $tick = $(stream_row).find("svg"); + $tick.addClass("hide"); + + /* Add a spinner to show the request is in process. */ + const $spinner = $(stream_row).find(".sub_unsub_status").expectOne(); + $spinner.show(); + loading.make_indicator($spinner); +} + +/* For the given stream_row, add the tick and delete the spinner. */ +function hide_subscribe_toggle_spinner(stream_row) { + /* Re-enable the button to handle requests. */ + $(stream_row).find(".check").addClass("sub_unsub_button"); + + /* Show the tick. */ + const $tick = $(stream_row).find("svg"); + $tick.removeClass("hide"); + + /* Destroy the spinner. */ + const $spinner = $(stream_row).find(".sub_unsub_status").expectOne(); + loading.destroy_indicator($spinner); +} + +export function ajaxSubscribe(stream, color, $stream_row) { + // Subscribe yourself to a single stream. + let true_stream_name; + + if ($stream_row !== undefined) { + display_subscribe_toggle_spinner($stream_row); + } + return channel.post({ + url: "/json/users/me/subscriptions", + data: {subscriptions: JSON.stringify([{name: stream, color}])}, + success(_resp, _statusText, xhr) { + if (overlays.streams_open()) { + $("#create_stream_name").val(""); + } + + const res = xhr.responseJSON; + if (!$.isEmptyObject(res.already_subscribed)) { + // Display the canonical stream capitalization. + true_stream_name = res.already_subscribed[people.my_current_email()][0]; + ui_report.success( + $t_html( + {defaultMessage: "Already subscribed to {stream}"}, + {stream: true_stream_name}, + ), + $(".stream_change_property_info"), + ); + } + // The rest of the work is done via the subscribe event we will get + + if ($stream_row !== undefined) { + hide_subscribe_toggle_spinner($stream_row); + } + }, + error(xhr) { + if ($stream_row !== undefined) { + hide_subscribe_toggle_spinner($stream_row); + } + ui_report.error( + $t_html({defaultMessage: "Error adding subscription"}), + xhr, + $(".stream_change_property_info"), + ); + }, + }); +} + +function ajaxUnsubscribe(sub, $stream_row) { + // TODO: use stream_id when backend supports it + if ($stream_row !== undefined) { + display_subscribe_toggle_spinner($stream_row); + } + return channel.del({ + url: "/json/users/me/subscriptions", + data: {subscriptions: JSON.stringify([sub.name])}, + success() { + $(".stream_change_property_info").hide(); + // The rest of the work is done via the unsubscribe event we will get + + if ($stream_row !== undefined) { + hide_subscribe_toggle_spinner($stream_row); + } + }, + error(xhr) { + if ($stream_row !== undefined) { + hide_subscribe_toggle_spinner($stream_row); + } + ui_report.error( + $t_html({defaultMessage: "Error removing subscription"}), + xhr, + $(".stream_change_property_info"), + ); + }, + }); +} + +export function unsubscribe_from_private_stream(sub) { + const invite_only = sub.invite_only; + const sub_count = peer_data.get_subscriber_count(sub.stream_id); + const stream_name_with_privacy_symbol_html = render_inline_decorated_stream_name({stream: sub}); + + const html_body = render_unsubscribe_private_stream_modal({ + message: $t({ + defaultMessage: "Once you leave this stream, you will not be able to rejoin.", + }), + display_stream_archive_warning: sub_count === 1 && invite_only, + }); + + function unsubscribe_from_stream() { + let $stream_row; + if (overlays.streams_open()) { + $stream_row = $( + "#streams_overlay_container div.stream-row[data-stream-id='" + sub.stream_id + "']", + ); + } + + ajaxUnsubscribe(sub, $stream_row); + } + + confirm_dialog.launch({ + html_heading: $t_html( + {defaultMessage: "Unsubscribe from "}, + {"z-link": () => stream_name_with_privacy_symbol_html}, + ), + html_body, + on_click: unsubscribe_from_stream, + }); +} + +export function sub_or_unsub(sub, $stream_row) { + if (sub.subscribed) { + // TODO: This next line should allow guests to access web-public streams. + if (sub.invite_only || page_params.is_guest) { + unsubscribe_from_private_stream(sub); + return; + } + ajaxUnsubscribe(sub, $stream_row); + } else { + ajaxSubscribe(sub.name, sub.color, $stream_row); + } +} + +export function update_public_stream_privacy_option_state($container) { + const $public_stream_elem = $container.find( + `input[value='${CSS.escape(settings_config.stream_privacy_policy_values.public.code)}']`, + ); + $public_stream_elem.prop("disabled", !settings_data.user_can_create_public_streams()); +} + +export function hide_or_disable_stream_privacy_options_if_required($container) { + stream_ui_updates.update_web_public_stream_privacy_option_state($container); + + update_public_stream_privacy_option_state($container); + + stream_ui_updates.update_private_stream_privacy_option_state($container); +} diff --git a/web/src/stream_settings_ui.js b/web/src/stream_settings_ui.js index ba16ef83f6..d0811e595f 100644 --- a/web/src/stream_settings_ui.js +++ b/web/src/stream_settings_ui.js @@ -1,34 +1,25 @@ import $ from "jquery"; import _ from "lodash"; -import render_unsubscribe_private_stream_modal from "../templates/confirm_dialog/confirm_unsubscribe_private_stream.hbs"; -import render_inline_decorated_stream_name from "../templates/inline_decorated_stream_name.hbs"; import render_browse_streams_list from "../templates/stream_settings/browse_streams_list.hbs"; import render_browse_streams_list_item from "../templates/stream_settings/browse_streams_list_item.hbs"; -import render_selected_stream_title from "../templates/stream_settings/selected_stream_title.hbs"; import render_stream_settings from "../templates/stream_settings/stream_settings.hbs"; import render_stream_settings_overlay from "../templates/stream_settings/stream_settings_overlay.hbs"; import * as blueslip from "./blueslip"; import * as browser_history from "./browser_history"; -import * as channel from "./channel"; import * as components from "./components"; import * as compose_recipient from "./compose_recipient"; import * as compose_state from "./compose_state"; -import * as confirm_dialog from "./confirm_dialog"; -import * as dropdown_widget from "./dropdown_widget"; import * as hash_parser from "./hash_parser"; import * as hash_util from "./hash_util"; -import {$t, $t_html} from "./i18n"; +import {$t} from "./i18n"; import * as keydown_util from "./keydown_util"; -import * as loading from "./loading"; import * as message_lists from "./message_lists"; import * as message_live_update from "./message_live_update"; import * as message_view_header from "./message_view_header"; import * as overlays from "./overlays"; import {page_params} from "./page_params"; -import * as peer_data from "./peer_data"; -import * as people from "./people"; import * as scroll_util from "./scroll_util"; import * as search_util from "./search_util"; import * as settings_config from "./settings_config"; @@ -39,41 +30,12 @@ import * as stream_edit from "./stream_edit"; import * as stream_edit_subscribers from "./stream_edit_subscribers"; import * as stream_list from "./stream_list"; import * as stream_settings_api from "./stream_settings_api"; +import * as stream_settings_components from "./stream_settings_components"; import * as stream_settings_data from "./stream_settings_data"; import * as stream_ui_updates from "./stream_ui_updates"; import * as sub_store from "./sub_store"; -import * as ui_report from "./ui_report"; -import * as user_groups from "./user_groups"; import * as util from "./util"; -export function set_right_panel_title(sub) { - let title_icon_color = "#333333"; - if (settings_data.using_dark_theme()) { - title_icon_color = "#dddeee"; - } - $("#subscription_overlay .stream-info-title").html( - render_selected_stream_title({sub, title_icon_color}), - ); -} - -export const show_subs_pane = { - nothing_selected() { - $(".settings, #stream-creation").hide(); - $(".nothing-selected").show(); - $("#subscription_overlay .stream-info-title").text($t({defaultMessage: "Stream settings"})); - }, - settings(sub) { - $(".settings, #stream-creation").hide(); - $(".settings").show(); - set_right_panel_title(sub); - }, - create_stream() { - $(".nothing-selected, .settings, #stream-creation").hide(); - $("#stream-creation").show(); - $("#subscription_overlay .stream-info-title").text($t({defaultMessage: "Create stream"})); - }, -}; - export function is_sub_already_present(sub) { return stream_ui_updates.row_for_stream_id(sub.stream_id).length > 0; } @@ -115,17 +77,6 @@ function get_row_data($row) { return undefined; } -export function get_active_data() { - const $active_row = $("div.stream-row.active"); - const valid_active_id = Number.parseInt($active_row.attr("data-stream-id"), 10); - const $active_tabs = $(".subscriptions-container").find("div.ind-tab.selected"); - return { - $row: $active_row, - id: valid_active_id, - $tabs: $active_tabs, - }; -} - function selectText(element) { const sel = window.getSelection(); const range = document.createRange(); @@ -201,9 +152,9 @@ export function update_stream_privacy(slim_sub, values) { stream_ui_updates.enable_or_disable_subscribers_tab(sub); stream_list.redraw_stream_privacy(sub); - const active_data = get_active_data(); + const active_data = stream_settings_components.get_active_data(); if (active_data.id === sub.stream_id) { - set_right_panel_title(sub); + stream_settings_components.set_right_panel_title(sub); } // Update navbar if needed @@ -227,7 +178,7 @@ export function update_can_remove_subscribers_group_id(sub, new_value) { } export function update_is_default_stream() { - const active_stream_id = get_active_data().id; + const active_stream_id = stream_settings_components.get_active_data().id; if (active_stream_id) { const sub = sub_store.get(active_stream_id); stream_ui_updates.update_setting_element(sub, "is_default_stream"); @@ -565,34 +516,6 @@ export function switch_stream_sort(tab_name) { redraw_left_panel(); } -export let new_stream_can_remove_subscribers_group_widget = null; - -function dropdown_setup() { - new_stream_can_remove_subscribers_group_widget = new dropdown_widget.DropdownWidget({ - widget_name: "new_stream_can_remove_subscribers_group", - get_options: () => - user_groups.get_realm_user_groups_for_dropdown_list_widget( - "can_remove_subscribers_group", - ), - item_click_callback(event, dropdown) { - dropdown.hide(); - event.preventDefault(); - event.stopPropagation(); - new_stream_can_remove_subscribers_group_widget.render(); - }, - $events_container: $("#subscription_overlay"), - tippy_props: { - placement: "bottom-start", - }, - on_mount_callback(dropdown) { - $(dropdown.popper).css("min-width", "300px"); - }, - default_text: $t({defaultMessage: "No user groups"}), - default_id: user_groups.get_user_group_from_name("role:administrators").id, - unique_id_type: dropdown_widget.DATA_TYPES.NUMBER, - }); -} - export function setup_page(callback) { // We should strongly consider only setting up the page once, // but I am writing these comments write before a big release, @@ -705,7 +628,7 @@ export function setup_page(callback) { render_left_panel_superset(); initialize_components(); - dropdown_setup(); + stream_settings_components.dropdown_setup(); redraw_left_panel(); stream_create.set_up_handlers(); @@ -759,14 +682,14 @@ export function switch_to_stream_row(stream_id) { const $stream_row = stream_ui_updates.row_for_stream_id(stream_id); const $container = $(".streams-list"); - get_active_data().$row.removeClass("active"); + stream_settings_components.get_active_data().$row.removeClass("active"); $stream_row.addClass("active"); scroll_util.scroll_element_into_container($stream_row, $container); // It's dubious that we need this timeout any more. setTimeout(() => { - if (stream_id === get_active_data().id) { + if (stream_id === stream_settings_components.get_active_data().id) { $stream_row.trigger("click"); } }, 100); @@ -836,7 +759,7 @@ export function launch(section) { }); change_state(section); }); - if (!get_active_data().id) { + if (!stream_settings_components.get_active_data().id) { if (section === "new") { $("#create_stream_name").trigger("focus"); } else { @@ -846,7 +769,7 @@ export function launch(section) { } export function switch_rows(event) { - const active_data = get_active_data(); + const active_data = stream_settings_components.get_active_data(); let $switch_row; if (hash_parser.is_create_new_stream_narrow()) { // Prevent switching stream rows when creating a new stream @@ -880,15 +803,15 @@ export function switch_rows(event) { } export function keyboard_sub() { - const active_data = get_active_data(); + const active_data = stream_settings_components.get_active_data(); const row_data = get_row_data(active_data.$row); if (row_data) { - sub_or_unsub(row_data.object); + stream_settings_components.sub_or_unsub(row_data.object); } } export function toggle_view(event) { - const active_data = get_active_data(); + const active_data = stream_settings_components.get_active_data(); const stream_filter_tab = active_data.$tabs.first().text(); if (event === "right_arrow" && stream_filter_tab === "Subscribed") { @@ -899,7 +822,7 @@ export function toggle_view(event) { } export function view_stream() { - const active_data = get_active_data(); + const active_data = stream_settings_components.get_active_data(); const row_data = get_row_data(active_data.$row); if (row_data) { const stream_narrow_hash = @@ -908,110 +831,6 @@ export function view_stream() { } } -/* For the given stream_row, remove the tick and replace by a spinner. */ -function display_subscribe_toggle_spinner(stream_row) { - /* Prevent sending multiple requests by removing the button class. */ - $(stream_row).find(".check").removeClass("sub_unsub_button"); - - /* Hide the tick. */ - const $tick = $(stream_row).find("svg"); - $tick.addClass("hide"); - - /* Add a spinner to show the request is in process. */ - const $spinner = $(stream_row).find(".sub_unsub_status").expectOne(); - $spinner.show(); - loading.make_indicator($spinner); -} - -/* For the given stream_row, add the tick and delete the spinner. */ -function hide_subscribe_toggle_spinner(stream_row) { - /* Re-enable the button to handle requests. */ - $(stream_row).find(".check").addClass("sub_unsub_button"); - - /* Show the tick. */ - const $tick = $(stream_row).find("svg"); - $tick.removeClass("hide"); - - /* Destroy the spinner. */ - const $spinner = $(stream_row).find(".sub_unsub_status").expectOne(); - loading.destroy_indicator($spinner); -} - -function ajaxSubscribe(stream, color, $stream_row) { - // Subscribe yourself to a single stream. - let true_stream_name; - - if ($stream_row !== undefined) { - display_subscribe_toggle_spinner($stream_row); - } - return channel.post({ - url: "/json/users/me/subscriptions", - data: {subscriptions: JSON.stringify([{name: stream, color}])}, - success(_resp, _statusText, xhr) { - if (overlays.streams_open()) { - $("#create_stream_name").val(""); - } - - const res = xhr.responseJSON; - if (!$.isEmptyObject(res.already_subscribed)) { - // Display the canonical stream capitalization. - true_stream_name = res.already_subscribed[people.my_current_email()][0]; - ui_report.success( - $t_html( - {defaultMessage: "Already subscribed to {stream}"}, - {stream: true_stream_name}, - ), - $(".stream_change_property_info"), - ); - } - // The rest of the work is done via the subscribe event we will get - - if ($stream_row !== undefined) { - hide_subscribe_toggle_spinner($stream_row); - } - }, - error(xhr) { - if ($stream_row !== undefined) { - hide_subscribe_toggle_spinner($stream_row); - } - ui_report.error( - $t_html({defaultMessage: "Error adding subscription"}), - xhr, - $(".stream_change_property_info"), - ); - }, - }); -} - -function ajaxUnsubscribe(sub, $stream_row) { - // TODO: use stream_id when backend supports it - if ($stream_row !== undefined) { - display_subscribe_toggle_spinner($stream_row); - } - return channel.del({ - url: "/json/users/me/subscriptions", - data: {subscriptions: JSON.stringify([sub.name])}, - success() { - $(".stream_change_property_info").hide(); - // The rest of the work is done via the unsubscribe event we will get - - if ($stream_row !== undefined) { - hide_subscribe_toggle_spinner($stream_row); - } - }, - error(xhr) { - if ($stream_row !== undefined) { - hide_subscribe_toggle_spinner($stream_row); - } - ui_report.error( - $t_html({defaultMessage: "Error removing subscription"}), - xhr, - $(".stream_change_property_info"), - ); - }, - }); -} - export function do_open_create_stream() { // Only call this directly for hash changes. // Prefer open_create_stream(). @@ -1021,7 +840,7 @@ export function do_open_create_stream() { if (!should_list_all_streams()) { // Realms that don't allow listing streams should simply be subscribed to. stream_create.set_name(stream); - ajaxSubscribe($("#search_stream_name").val()); + stream_settings_components.ajaxSubscribe($("#search_stream_name").val()); return; } @@ -1033,67 +852,6 @@ export function open_create_stream() { browser_history.update("#streams/new"); } -export function unsubscribe_from_private_stream(sub) { - const invite_only = sub.invite_only; - const sub_count = peer_data.get_subscriber_count(sub.stream_id); - const stream_name_with_privacy_symbol_html = render_inline_decorated_stream_name({stream: sub}); - - const html_body = render_unsubscribe_private_stream_modal({ - message: $t({ - defaultMessage: "Once you leave this stream, you will not be able to rejoin.", - }), - display_stream_archive_warning: sub_count === 1 && invite_only, - }); - - function unsubscribe_from_stream() { - let $stream_row; - if (overlays.streams_open()) { - $stream_row = $( - "#streams_overlay_container div.stream-row[data-stream-id='" + sub.stream_id + "']", - ); - } - - ajaxUnsubscribe(sub, $stream_row); - } - - confirm_dialog.launch({ - html_heading: $t_html( - {defaultMessage: "Unsubscribe from "}, - {"z-link": () => stream_name_with_privacy_symbol_html}, - ), - html_body, - on_click: unsubscribe_from_stream, - }); -} - -export function sub_or_unsub(sub, $stream_row) { - if (sub.subscribed) { - // TODO: This next line should allow guests to access web-public streams. - if (sub.invite_only || page_params.is_guest) { - unsubscribe_from_private_stream(sub); - return; - } - ajaxUnsubscribe(sub, $stream_row); - } else { - ajaxSubscribe(sub.name, sub.color, $stream_row); - } -} - -export function update_public_stream_privacy_option_state($container) { - const $public_stream_elem = $container.find( - `input[value='${CSS.escape(settings_config.stream_privacy_policy_values.public.code)}']`, - ); - $public_stream_elem.prop("disabled", !settings_data.user_can_create_public_streams()); -} - -export function hide_or_disable_stream_privacy_options_if_required($container) { - stream_ui_updates.update_web_public_stream_privacy_option_state($container); - - update_public_stream_privacy_option_state($container); - - stream_ui_updates.update_private_stream_privacy_option_state($container); -} - export function update_stream_privacy_choices(policy) { if (!overlays.streams_open()) { return; @@ -1113,7 +871,7 @@ export function update_stream_privacy_choices(policy) { stream_ui_updates.update_private_stream_privacy_option_state($container); } if (policy === "create_public_stream_policy") { - update_public_stream_privacy_option_state($container); + stream_settings_components.update_public_stream_privacy_option_state($container); } if (policy === "create_web_public_stream_policy") { stream_ui_updates.update_web_public_stream_privacy_option_state($container);