mirror of
https://github.com/discourse/discourse.git
synced 2024-12-22 23:16:03 +08:00
ed2dae6d1a
When the loading slider is enabled, the rendering of `application.hbs` is slightly delayed compared to the old 'spinner' strategy. This means that if a route tried to render a dialog during its `model()` hook, the dialog wrapper element would not be present and an error would occur. This commit detects that situation and delays rendering the error until the next runloop iteration. If the element is still not found, we print a useful error to the console. In the long term, we should ideally convert the dialog service to use a pure-ember rendering strategy instead of leaning on a11y-dialog. But for now, this workaround should resolve the problems identified by the chat system specs.
201 lines
3.9 KiB
JavaScript
201 lines
3.9 KiB
JavaScript
import Service from "@ember/service";
|
|
import A11yDialog from "a11y-dialog";
|
|
import { bind } from "discourse-common/utils/decorators";
|
|
import { next } from "@ember/runloop";
|
|
|
|
export default Service.extend({
|
|
dialogInstance: null,
|
|
message: null,
|
|
title: null,
|
|
titleElementId: null,
|
|
type: null,
|
|
|
|
bodyComponent: null,
|
|
bodyComponentModel: null,
|
|
|
|
confirmButtonIcon: null,
|
|
confirmButtonLabel: null,
|
|
confirmButtonClass: null,
|
|
confirmButtonDisabled: false,
|
|
cancelButtonLabel: null,
|
|
cancelButtonClass: null,
|
|
shouldDisplayCancel: null,
|
|
|
|
didConfirm: null,
|
|
didCancel: null,
|
|
buttons: null,
|
|
class: null,
|
|
_confirming: false,
|
|
|
|
async dialog(params) {
|
|
const {
|
|
message,
|
|
bodyComponent,
|
|
bodyComponentModel,
|
|
type,
|
|
title,
|
|
|
|
confirmButtonClass = "btn-primary",
|
|
confirmButtonIcon,
|
|
confirmButtonLabel = "ok_value",
|
|
confirmButtonDisabled = false,
|
|
|
|
cancelButtonClass = "btn-default",
|
|
cancelButtonLabel = "cancel_value",
|
|
shouldDisplayCancel,
|
|
|
|
didConfirm,
|
|
didCancel,
|
|
buttons,
|
|
} = params;
|
|
|
|
let element = document.getElementById("dialog-holder");
|
|
if (!element) {
|
|
await new Promise((resolve) => next(resolve));
|
|
element = document.getElementById("dialog-holder");
|
|
}
|
|
|
|
if (!element) {
|
|
const msg =
|
|
"dialog-holder wrapper element not found. Unable to render dialog";
|
|
// eslint-disable-next-line no-console
|
|
console.error(msg, params);
|
|
throw new Error(msg);
|
|
}
|
|
|
|
this.setProperties({
|
|
message,
|
|
bodyComponent,
|
|
bodyComponentModel,
|
|
type,
|
|
dialogInstance: new A11yDialog(element),
|
|
|
|
title,
|
|
titleElementId: title !== null ? "dialog-title" : null,
|
|
|
|
confirmButtonClass,
|
|
confirmButtonDisabled,
|
|
confirmButtonIcon,
|
|
confirmButtonLabel,
|
|
|
|
cancelButtonClass,
|
|
cancelButtonLabel,
|
|
shouldDisplayCancel,
|
|
|
|
didConfirm,
|
|
didCancel,
|
|
buttons,
|
|
class: params.class,
|
|
});
|
|
|
|
this.dialogInstance.show();
|
|
|
|
this.dialogInstance.on("hide", () => {
|
|
if (!this._confirming && this.didCancel) {
|
|
this.didCancel();
|
|
}
|
|
|
|
this.reset();
|
|
});
|
|
},
|
|
|
|
alert(params) {
|
|
// support string param for easier porting of bootbox.alert
|
|
if (typeof params === "string") {
|
|
return this.dialog({
|
|
message: params,
|
|
type: "alert",
|
|
});
|
|
}
|
|
|
|
return this.dialog({
|
|
...params,
|
|
type: "alert",
|
|
});
|
|
},
|
|
|
|
confirm(params) {
|
|
return this.dialog({
|
|
...params,
|
|
shouldDisplayCancel: true,
|
|
buttons: null,
|
|
type: "confirm",
|
|
});
|
|
},
|
|
|
|
notice(message) {
|
|
return this.dialog({
|
|
message,
|
|
type: "notice",
|
|
});
|
|
},
|
|
|
|
yesNoConfirm(params) {
|
|
return this.confirm({
|
|
...params,
|
|
confirmButtonLabel: "yes_value",
|
|
cancelButtonLabel: "no_value",
|
|
});
|
|
},
|
|
|
|
deleteConfirm(params) {
|
|
return this.confirm({
|
|
...params,
|
|
confirmButtonClass: "btn-danger",
|
|
confirmButtonLabel: params.confirmButtonLabel || "delete",
|
|
});
|
|
},
|
|
|
|
reset() {
|
|
this.setProperties({
|
|
message: null,
|
|
bodyComponent: null,
|
|
bodyComponentModel: null,
|
|
type: null,
|
|
dialogInstance: null,
|
|
|
|
title: null,
|
|
titleElementId: null,
|
|
|
|
confirmButtonDisabled: false,
|
|
confirmButtonIcon: null,
|
|
confirmButtonLabel: null,
|
|
|
|
cancelButtonClass: null,
|
|
cancelButtonLabel: null,
|
|
shouldDisplayCancel: null,
|
|
|
|
didConfirm: null,
|
|
didCancel: null,
|
|
buttons: null,
|
|
class: null,
|
|
|
|
_confirming: false,
|
|
});
|
|
},
|
|
|
|
willDestroy() {
|
|
this.dialogInstance?.destroy();
|
|
this.reset();
|
|
},
|
|
|
|
@bind
|
|
didConfirmWrapped() {
|
|
if (this.didConfirm) {
|
|
this.didConfirm();
|
|
}
|
|
this._confirming = true;
|
|
this.dialogInstance.hide();
|
|
},
|
|
|
|
@bind
|
|
cancel() {
|
|
this.dialogInstance.hide();
|
|
},
|
|
|
|
@bind
|
|
enableConfirmButton() {
|
|
this.set("confirmButtonDisabled", false);
|
|
},
|
|
});
|