frontend: Add dialog_widget module and refactor confirm_dialog.

This commit adds a new dialog_widget.js file containing most
of the code of confirm_dialog.js with some minor changes and
changes confirm_dialog to be a wrapper around dialog_widget.js.
We pass 'is_confim_dialog' as true in dialog_widget for a
confirm_dialog modal. This commit also renames confirm_dialog.hbs
and confirm_dialog_heading.hbs to dialog_widget.js,
dialog_widget.hbs and dialog_widget_heading.hbs respectively.
This commit is contained in:
sahil839 2021-07-05 22:45:37 +05:30 committed by Tim Abbott
parent 71969f5196
commit ec3c5547ff
8 changed files with 141 additions and 131 deletions

View File

@ -1,129 +1,5 @@
import $ from "jquery";
import render_dialog_widget from "../templates/confirm_dialog.hbs";
import render_dialog_heading from "../templates/confirm_dialog_heading.hbs";
import * as blueslip from "./blueslip";
import * as overlays from "./overlays";
import * as settings_data from "./settings_data";
/*
Look for confirm_dialog in settings_user_groups
to see an example of how to use this widget. It's
pretty simple to use!
Some things to note:
1) We create DOM on the fly, and we remove
the DOM once it's closed.
2) We attach the DOM for the modal to conf.parent,
and this temporary DOM location will influence
how styles work.
3) The cancel button is driven by bootstrap.js.
4) For settings, we have a click handler in settings.js
that will close the dialog via overlays.close_active_modal.
5) We assume that since this is a modal, you will
only ever have one dialog active at any
time.
6) If a modal wants a loading spinner, it should pass loading_spinner: true.
This will show a loading spinner when the yes button is clicked.
The caller is responsible for calling hide_dialog_spinner()
to hide the spinner in both success and error handlers.
7) If a caller needs to run code after the modal body is added
to DOM, it can do so by passing a post_render hook.
*/
export function hide_dialog_spinner() {
$(".dialog_submit_button .loader").hide();
$(".dialog_submit_button span").show();
$(".dialog_submit_button").prop("disabled", false);
$("#dialog_widget_modal .close-modal-btn").prop("disabled", false);
}
export function show_dialog_spinner() {
$(".dialog_submit_button .loader").css("display", "inline-block");
$(".dialog_submit_button span").hide();
$(".dialog_submit_button").prop("disabled", true);
$("#dialog_widget_modal .close-modal-btn").prop("disabled", true);
if (!settings_data.using_dark_theme()) {
$(".dialog_submit_button object").on("load", function () {
const doc = this.getSVGDocument();
const $svg = $(doc).find("svg");
$svg.find("rect").css("fill", "#000");
});
}
}
import * as dialog_widget from "./dialog_widget";
export function launch(conf) {
const html = render_dialog_widget({fade: conf.fade});
const dialog = $(html);
const conf_fields = [
// The next three fields should be safe HTML. If callers
// interpolate user data into strings, they should use
// templates.
"html_heading",
"html_body",
"html_submit_button",
"on_click",
"parent",
];
for (const f of conf_fields) {
if (conf[f] === undefined) {
blueslip.error("programmer omitted " + f);
}
}
conf.parent.append(dialog);
// Close any existing modals--on settings screens you can
// have multiple buttons that need confirmation.
if (overlays.is_modal_open()) {
overlays.close_modal("#dialog_widget_modal");
}
dialog.find(".dialog_heading").html(
render_dialog_heading({
heading_text: conf.html_heading,
link: conf.help_link,
}),
);
dialog.find(".dialog_body").append(conf.html_body);
const submit_button_span = dialog.find(".dialog_submit_button span");
submit_button_span.html(conf.html_submit_button);
if (conf.post_render !== undefined) {
conf.post_render();
}
const submit_button = dialog.find(".dialog_submit_button");
// Set up handlers.
submit_button.on("click", () => {
if (conf.loading_spinner) {
show_dialog_spinner();
} else {
overlays.close_modal("#dialog_widget_modal");
}
conf.on_click();
});
dialog.on("hidden.bs.modal", () => {
dialog.remove();
});
// Open the modal
overlays.open_modal("#dialog_widget_modal");
conf.parent.on("shown.bs.modal", () => {
submit_button.trigger("focus");
});
dialog_widget.launch({...conf, is_confirm_dialog: true});
}

131
static/js/dialog_widget.js Normal file
View File

@ -0,0 +1,131 @@
import $ from "jquery";
import render_dialog_widget from "../templates/dialog_widget.hbs";
import render_dialog_heading from "../templates/dialog_widget_heading.hbs";
import * as blueslip from "./blueslip";
import * as overlays from "./overlays";
import * as settings_data from "./settings_data";
/*
Look for dialog_widget in settings_users
to see an example of how to use this widget. It's
pretty simple to use!
Some things to note:
1) We create DOM on the fly, and we remove
the DOM once it's closed.
2) We attach the DOM for the modal to conf.parent,
and this temporary DOM location will influence
how styles work.
3) The cancel button is driven by bootstrap.js.
4) For settings, we have a click handler in settings.js
that will close the dialog via overlays.close_active_modal.
5) We assume that since this is a modal, you will
only ever have one dialog active at any
time.
6) If a modal wants a loading spinner, it should pass loading_spinner: true.
This will show a loading spinner when the yes button is clicked.
The caller is responsible for calling hide_dialog_spinner()
to hide the spinner in both success and error handlers.
7) If a caller needs to run code after the modal body is added
to DOM, it can do so by passing a post_render hook.
*/
export function hide_dialog_spinner() {
$(".dialog_submit_button .loader").hide();
$(".dialog_submit_button span").show();
$(".dialog_submit_button").prop("disabled", false);
$("#dialog_widget_modal .close-modal-btn").prop("disabled", false);
}
export function show_dialog_spinner() {
$(".dialog_submit_button .loader").css("display", "inline-block");
$(".dialog_submit_button span").hide();
$(".dialog_submit_button").prop("disabled", true);
$("#dialog_widget_modal .close-modal-btn").prop("disabled", true);
if (!settings_data.using_dark_theme()) {
$(".dialog_submit_button object").on("load", function () {
const doc = this.getSVGDocument();
const $svg = $(doc).find("svg");
$svg.find("rect").css("fill", "#000");
});
}
}
export function launch(conf) {
const html = render_dialog_widget({fade: conf.fade});
const dialog = $(html);
const conf_fields = [
// The next three fields should be safe HTML. If callers
// interpolate user data into strings, they should use
// templates.
"html_heading",
"html_body",
"html_submit_button",
"on_click",
"parent",
];
for (const f of conf_fields) {
if (conf[f] === undefined) {
blueslip.error("programmer omitted " + f);
}
}
conf.parent.append(dialog);
// Close any existing modals--on settings screens you can
// have multiple buttons that need confirmation.
if (overlays.is_modal_open()) {
overlays.close_modal("#dialog_widget_modal");
}
dialog.find(".dialog_heading").html(
render_dialog_heading({
heading_text: conf.html_heading,
link: conf.help_link,
}),
);
dialog.find(".dialog_body").append(conf.html_body);
const submit_button_span = dialog.find(".dialog_submit_button span");
submit_button_span.html(conf.html_submit_button);
if (conf.post_render !== undefined) {
conf.post_render();
}
const submit_button = dialog.find(".dialog_submit_button");
// Set up handlers.
submit_button.on("click", () => {
if (conf.loading_spinner) {
show_dialog_spinner();
} else if (conf.is_confirm_dialog) {
overlays.close_modal("#dialog_widget_modal");
}
conf.on_click();
});
dialog.on("hidden.bs.modal", () => {
dialog.remove();
});
// Open the modal
overlays.open_modal("#dialog_widget_modal");
if (conf.is_confirm_dialog) {
conf.parent.on("shown.bs.modal", () => {
submit_button.trigger("focus");
});
}
}

View File

@ -13,6 +13,7 @@ import * as compose_actions from "./compose_actions";
import * as composebox_typeahead from "./composebox_typeahead";
import * as condense from "./condense";
import * as confirm_dialog from "./confirm_dialog";
import * as dialog_widget from "./dialog_widget";
import * as echo from "./echo";
import * as giphy from "./giphy";
import {$t, $t_html} from "./i18n";
@ -981,7 +982,7 @@ export function delete_message(msg_id) {
currently_deleting_messages = currently_deleting_messages.filter(
(id) => id !== msg_id,
);
confirm_dialog.hide_dialog_spinner();
dialog_widget.hide_dialog_spinner();
overlays.close_modal("#dialog_widget_modal");
},
error(xhr) {
@ -989,7 +990,7 @@ export function delete_message(msg_id) {
(id) => id !== msg_id,
);
confirm_dialog.hide_dialog_spinner();
dialog_widget.hide_dialog_spinner();
ui_report.error(
$t_html({defaultMessage: "Error deleting message"}),
xhr,

View File

@ -12,6 +12,7 @@ import * as channel from "./channel";
import * as common from "./common";
import * as confirm_dialog from "./confirm_dialog";
import {csrf_token} from "./csrf";
import * as dialog_widget from "./dialog_widget";
import {$t_html} from "./i18n";
import * as overlays from "./overlays";
import {page_params} from "./page_params";
@ -561,7 +562,7 @@ export function set_up() {
channel.del({
url: "/json/users/me",
success() {
confirm_dialog.hide_dialog_spinner();
dialog_widget.hide_dialog_spinner();
overlays.close_modal("#dialog_widget_modal");
window.location.href = "/login/";
},
@ -587,7 +588,7 @@ export function set_up() {
rendered_error_msg = error_last_user;
}
}
confirm_dialog.hide_dialog_spinner();
dialog_widget.hide_dialog_spinner();
overlays.close_modal("#dialog_widget_modal");
$("#account-settings-status")
.addClass("alert-error")

View File

@ -130,7 +130,7 @@ js_rules = RuleList(
"static/js/portico",
"static/js/lightbox.js",
"static/js/ui_report.ts",
"static/js/confirm_dialog.js",
"static/js/dialog_widget.js",
"static/js/edit_fields_modal.js",
"frontend_tests/",
},

View File

@ -53,6 +53,7 @@ EXEMPT_FILES = {
"static/js/compose.js",
"static/js/condense.js",
"static/js/confirm_dialog.js",
"static/js/dialog_widget.js",
"static/js/copy_and_paste.js",
"static/js/csrf.ts",
"static/js/css_variables.js",