diff --git a/web/e2e-tests/custom-profile.test.ts b/web/e2e-tests/custom-profile.test.ts index 5553eb89ff..e2cb6bc437 100644 --- a/web/e2e-tests/custom-profile.test.ts +++ b/web/e2e-tests/custom-profile.test.ts @@ -15,7 +15,7 @@ async function test_add_new_profile_field(page: Page): Promise { "Add a new custom profile field", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Add", ); await page.waitForSelector(".admin-profile-field-form", {visible: true}); @@ -23,7 +23,7 @@ async function test_add_new_profile_field(page: Page): Promise { field_type: "1", name: "Teams", }); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); await page.waitForSelector( @@ -43,13 +43,13 @@ async function test_edit_profile_field(page: Page): Promise { "Edit custom profile field", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Save changes", ); await common.fill_form(page, "form.name-setting", { name: "team", }); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); await page.waitForSelector( @@ -69,10 +69,10 @@ async function test_delete_custom_profile_field(page: Page): Promise { "Delete custom profile field?", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Confirm", ); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); await page.waitForSelector("#admin-profile-field-status img", {visible: true}); diff --git a/web/e2e-tests/realm-linkifier.test.ts b/web/e2e-tests/realm-linkifier.test.ts index 121fa1f6e3..9394b01273 100644 --- a/web/e2e-tests/realm-linkifier.test.ts +++ b/web/e2e-tests/realm-linkifier.test.ts @@ -70,7 +70,7 @@ async function test_edit_linkifier(page: Page): Promise { }); await page.click(".dialog_submit_button"); - await page.waitForSelector("#dialog_widget_modal", {hidden: true}); + await page.waitForSelector(".micromodal", {hidden: true}); await common.wait_for_micromodal_to_close(page); await page.waitForSelector(".linkifier_row:nth-last-child(1)", {visible: true}); @@ -117,7 +117,7 @@ async function test_edit_invalid_linkifier(page: Page): Promise { assert.strictEqual(edit_linkifier_template_status, "Failed: Invalid URL template."); await page.click(".dialog_exit_button"); - await page.waitForSelector("#dialog_widget_modal", {hidden: true}); + await page.waitForSelector(".micromodal", {hidden: true}); await page.waitForSelector(".linkifier_row:nth-last-child(1)", {visible: true}); assert.strictEqual( diff --git a/web/e2e-tests/settings.test.ts b/web/e2e-tests/settings.test.ts index f38e9280f8..cace811082 100644 --- a/web/e2e-tests/settings.test.ts +++ b/web/e2e-tests/settings.test.ts @@ -111,7 +111,7 @@ async function test_webhook_bot_creation(page: Page): Promise { "Unexpected title for deactivate user modal", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Add", "Deactivate button has incorrect text.", ); @@ -121,7 +121,7 @@ async function test_webhook_bot_creation(page: Page): Promise { bot_type: OUTGOING_WEBHOOK_BOT_TYPE, payload_url: "http://hostname.example.com/bots/followup", }); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); const bot_email = "1-bot@zulip.testserver"; @@ -151,7 +151,7 @@ async function test_normal_bot_creation(page: Page): Promise { "Unexpected title for deactivate user modal", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Add", "Deactivate button has incorrect text.", ); @@ -160,7 +160,7 @@ async function test_normal_bot_creation(page: Page): Promise { bot_short_name: "2", bot_type: GENERIC_BOT_TYPE, }); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); const bot_email = "2-bot@zulip.testserver"; diff --git a/web/e2e-tests/user-deactivation.test.ts b/web/e2e-tests/user-deactivation.test.ts index 968940765a..2b0f881d7e 100644 --- a/web/e2e-tests/user-deactivation.test.ts +++ b/web/e2e-tests/user-deactivation.test.ts @@ -32,11 +32,11 @@ async function test_reactivation_confirmation_modal(page: Page, fullname: string "Unexpected title for reactivate user modal", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Confirm", "Reactivate button has incorrect text.", ); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); } @@ -53,11 +53,11 @@ async function test_deactivate_user(page: Page): Promise { "Unexpected title for deactivate user modal", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Deactivate", "Deactivate button has incorrect text.", ); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); } @@ -116,11 +116,11 @@ async function test_bot_deactivation_and_reactivation(page: Page): Promise "Unexpected title for deactivate bot modal", ); assert.strictEqual( - await common.get_text_from_selector(page, "#dialog_widget_modal .dialog_submit_button"), + await common.get_text_from_selector(page, ".micromodal .dialog_submit_button"), "Deactivate", "Deactivate button has incorrect text.", ); - await page.click("#dialog_widget_modal .dialog_submit_button"); + await page.click(".micromodal .dialog_submit_button"); await common.wait_for_micromodal_to_close(page); await page.waitForSelector(default_bot_user_row + ".deactivated_user", {visible: true}); diff --git a/web/src/confirm_dialog.ts b/web/src/confirm_dialog.ts index 159d5d6209..71b3fdeaae 100644 --- a/web/src/confirm_dialog.ts +++ b/web/src/confirm_dialog.ts @@ -2,8 +2,8 @@ import * as dialog_widget from "./dialog_widget"; import type {DialogWidgetConfig} from "./dialog_widget"; import {$t_html} from "./i18n"; -export function launch(conf: DialogWidgetConfig): void { - dialog_widget.launch({ +export function launch(conf: DialogWidgetConfig): string { + return dialog_widget.launch({ close_on_submit: true, focus_submit_on_open: true, html_submit_button: $t_html({defaultMessage: "Confirm"}), diff --git a/web/src/dialog_widget.ts b/web/src/dialog_widget.ts index cc07c2ab11..973572c17f 100644 --- a/web/src/dialog_widget.ts +++ b/web/src/dialog_widget.ts @@ -9,6 +9,21 @@ import * as loading from "./loading"; import * as modals from "./modals"; import * as ui_report from "./ui_report"; +// Since only one dialog widget can be active at a time +// and we don't support reopening already closed dialog widgets, +// this is also the id of the current / last open dialog widget. +// We will use this as id for current dialog widget assuming +// the caller has already checked that the dialog widget is open. +let widget_id_counter = 0; + +function current_dialog_widget_id(): string { + return `dialog_widget_modal_${widget_id_counter}`; +} + +function current_dialog_widget_selector(): string { + return `#${current_dialog_widget_id()}`; +} + /* * Look for confirm_dialog in settings_user_groups * to see an example of how to use this widget. It's @@ -60,7 +75,7 @@ export type DialogWidgetConfig = { on_shown?: () => void; on_hide?: () => void; on_hidden?: () => void; - post_render?: () => void; + post_render?: (modal_unique_id: string) => void; loading_spinner?: boolean; update_submit_disabled_state_on_change?: boolean; always_visible_scrollbar?: boolean; @@ -74,17 +89,19 @@ type RequestOpts = { export function hide_dialog_spinner(): void { $(".dialog_submit_button span").show(); - $("#dialog_widget_modal .modal__btn").prop("disabled", false); + const dialog_widget_selector = current_dialog_widget_selector(); + $(`${dialog_widget_selector} .modal__btn`).prop("disabled", false); - const $spinner = $("#dialog_widget_modal .modal__spinner"); + const $spinner = $(`${dialog_widget_selector} .modal__spinner`); loading.destroy_indicator($spinner); } export function show_dialog_spinner(): void { + const dialog_widget_selector = current_dialog_widget_selector(); // Disable both the buttons. - $("#dialog_widget_modal .modal__btn").prop("disabled", true); + $(`${dialog_widget_selector} .modal__btn`).prop("disabled", true); - const $spinner = $("#dialog_widget_modal .modal__spinner"); + const $spinner = $(`${dialog_widget_selector} .modal__spinner`); const dialog_submit_button_span_width = $(".dialog_submit_button span").width(); const dialog_submit_button_span_height = $(".dialog_submit_button span").height(); @@ -100,10 +117,10 @@ export function show_dialog_spinner(): void { // Supports a callback to be called once the modal finishes closing. export function close(on_hidden_callback?: () => void): void { - modals.close("dialog_widget_modal", {on_hidden: on_hidden_callback}); + modals.close(current_dialog_widget_id(), {on_hidden: on_hidden_callback}); } -export function launch(conf: DialogWidgetConfig): void { +export function launch(conf: DialogWidgetConfig): string { // Mandatory fields: // * html_heading // * html_body @@ -135,9 +152,12 @@ export function launch(conf: DialogWidgetConfig): void { // has scrollable content. Default behaviour is to hide the scrollbar when it is // not in use. + widget_id_counter += 1; + const modal_unique_id = current_dialog_widget_id(); const html_submit_button = conf.html_submit_button ?? $t_html({defaultMessage: "Save changes"}); const html_exit_button = conf.html_exit_button ?? $t_html({defaultMessage: "Cancel"}); const html = render_dialog_widget({ + modal_unique_id, heading_text: conf.html_heading, link: conf.help_link, html_submit_button, @@ -151,7 +171,7 @@ export function launch(conf: DialogWidgetConfig): void { $("body").append($dialog); if (conf.post_render !== undefined) { - conf.post_render(); + conf.post_render(modal_unique_id); } const $submit_button = $dialog.find(".dialog_submit_button"); @@ -219,7 +239,7 @@ export function launch(conf: DialogWidgetConfig): void { conf.on_click(e); }); - modals.open("dialog_widget_modal", { + modals.open(modal_unique_id, { autoremove: true, on_show() { if (conf.focus_submit_on_open) { @@ -233,6 +253,7 @@ export function launch(conf: DialogWidgetConfig): void { on_shown: conf?.on_shown, on_hidden: conf?.on_hidden, }); + return modal_unique_id; } export function submit_api_request( diff --git a/web/src/settings_linkifiers.ts b/web/src/settings_linkifiers.ts index 1d4ad92191..9e72b8f7cf 100644 --- a/web/src/settings_linkifiers.ts +++ b/web/src/settings_linkifiers.ts @@ -48,11 +48,11 @@ function open_linkifier_edit_form(linkifier_id: number): void { url_template: linkifier.url_template, }); - function submit_linkifier_form(): void { - const $change_linkifier_button = $(".dialog_submit_button"); + function submit_linkifier_form(dialog_widget_id: string): void { + const $modal = $(`#${dialog_widget_id}`); + const $change_linkifier_button = $modal.find(".dialog_submit_button"); $change_linkifier_button.prop("disabled", true); - const $modal = $("#dialog_widget_modal"); const url = "/json/realm/filters/" + encodeURIComponent(linkifier_id); const pattern = $modal.find("input#edit-linkifier-pattern").val()!.trim(); const url_template = $modal @@ -101,10 +101,12 @@ function open_linkifier_edit_form(linkifier_id: number): void { ); } - dialog_widget.launch({ + const dialog_widget_id = dialog_widget.launch({ html_heading: $t_html({defaultMessage: "Edit linkfiers"}), html_body, - on_click: submit_linkifier_form, + on_click() { + submit_linkifier_form(dialog_widget_id); + }, }); } diff --git a/web/src/unread_ops.ts b/web/src/unread_ops.ts index 83b737e3bc..0eebaaa2e1 100644 --- a/web/src/unread_ops.ts +++ b/web/src/unread_ops.ts @@ -52,10 +52,12 @@ export function is_window_focused(): boolean { export function confirm_mark_all_as_read(): void { const html_body = render_confirm_mark_all_as_read(); - confirm_dialog.launch({ + const modal_id = confirm_dialog.launch({ html_heading: $t_html({defaultMessage: "Mark all messages as read?"}), html_body, - on_click: mark_all_as_read, + on_click() { + mark_all_as_read(modal_id); + }, loading_spinner: true, }); } diff --git a/web/src/user_deactivation_ui.ts b/web/src/user_deactivation_ui.ts index d6bc1ddd20..ab03ce96de 100644 --- a/web/src/user_deactivation_ui.ts +++ b/web/src/user_deactivation_ui.ts @@ -51,9 +51,10 @@ export function confirm_deactivation( }; const html_body = render_settings_deactivation_user_modal(opts); - function set_email_field_visibility(): void { - const $send_email_checkbox = $("#dialog_widget_modal").find(".send_email"); - const $email_field = $("#dialog_widget_modal").find(".email_field"); + function set_email_field_visibility(dialog_widget_id: string): void { + const $modal = $(`#${dialog_widget_id}`); + const $send_email_checkbox = $modal.find(".send_email"); + const $email_field = $modal.find(".email_field"); $email_field.hide(); $send_email_checkbox.on("change", () => { diff --git a/web/templates/dialog_widget.hbs b/web/templates/dialog_widget.hbs index 063df4d9d8..d1b5f97693 100644 --- a/web/templates/dialog_widget.hbs +++ b/web/templates/dialog_widget.hbs @@ -1,4 +1,4 @@ -