diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js
index 7aa93052ead..14017465546 100644
--- a/app/assets/javascripts/discourse/app/controllers/composer.js
+++ b/app/assets/javascripts/discourse/app/controllers/composer.js
@@ -18,9 +18,7 @@ import discourseComputed, {
import DiscourseURL from "discourse/lib/url";
import Draft from "discourse/models/draft";
import I18n from "I18n";
-import { iconHTML } from "discourse-common/lib/icon-library";
import { Promise } from "rsvp";
-import bootbox from "bootbox";
import { buildQuote } from "discourse/lib/quote";
import deprecated from "discourse-common/lib/deprecated";
import discourseDebounce from "discourse-common/lib/debounce";
@@ -87,6 +85,7 @@ export function addPopupMenuOptionsCallback(callback) {
export default Controller.extend({
topicController: controller("topic"),
router: service(),
+ dialog: service(),
checkedMessages: false,
messageCount: null,
@@ -858,7 +857,7 @@ export default Controller.extend({
timeLeft: durationTextFromSeconds(timeLeft),
});
- bootbox.alert(message);
+ this.dialog.alert(message);
return;
} else {
// Edge case where the user tries to post again immediately.
@@ -885,40 +884,37 @@ export default Controller.extend({
currentTopic.id !== composer.get("topic.id") &&
(this.isStaffUser || !currentTopic.closed)
) {
- const message =
- "
" + I18n.t("composer.posting_not_on_topic") + "
";
-
- let buttons = [
- {
- label: I18n.t("composer.cancel"),
- class: "btn-flat btn-text btn-reply-where-cancel",
- },
- ];
-
- buttons.push({
- label:
- I18n.t("composer.reply_here") +
- "
" +
- currentTopic.get("fancyTitle") +
- "
",
- class: "btn-reply-here",
- callback: () => {
- composer.setProperties({ topic: currentTopic, post: null });
- this.save(true);
- },
+ this.dialog.alert({
+ title: I18n.t("composer.posting_not_on_topic"),
+ buttons: [
+ {
+ label:
+ I18n.t("composer.reply_original") +
+ "
" +
+ this.get("model.topic.fancyTitle") +
+ "
",
+ class: "btn-primary btn-reply-on-original",
+ action: () => this.save(true),
+ },
+ {
+ label:
+ I18n.t("composer.reply_here") +
+ "
" +
+ currentTopic.get("fancyTitle") +
+ "
",
+ class: "btn-reply-here",
+ action: () => {
+ composer.setProperties({ topic: currentTopic, post: null });
+ this.save(true);
+ },
+ },
+ {
+ label: I18n.t("composer.cancel"),
+ class: "btn-flat btn-text btn-reply-where-cancel",
+ },
+ ],
+ class: "reply-where-modal",
});
-
- buttons.push({
- label:
- I18n.t("composer.reply_original") +
- "
" +
- this.get("model.topic.fancyTitle") +
- "
",
- class: "btn-primary btn-reply-on-original",
- callback: () => this.save(true),
- });
-
- bootbox.dialog(message, buttons, { classes: "reply-where-modal" });
return;
}
}
@@ -987,8 +983,11 @@ export default Controller.extend({
// TODO: await this:
this.destroyDraft();
if (result.responseJson.message) {
- return bootbox.alert(result.responseJson.message, () => {
- DiscourseURL.routeTo(result.responseJson.route_to);
+ return this.dialog.alert({
+ message: result.responseJson.message,
+ didConfirm: () => {
+ DiscourseURL.routeTo(result.responseJson.route_to);
+ },
});
}
return DiscourseURL.routeTo(result.responseJson.route_to);
@@ -1010,7 +1009,9 @@ export default Controller.extend({
.catch((error) => {
composer.set("disableDrafts", false);
if (error) {
- this.appEvents.one("composer:will-open", () => bootbox.alert(error));
+ this.appEvents.one("composer:will-open", () =>
+ this.dialog.alert(error)
+ );
}
});
@@ -1295,23 +1296,27 @@ export default Controller.extend({
}
return new Promise((resolve) => {
- bootbox.dialog(I18n.t("drafts.abandon.confirm"), [
- {
- label: I18n.t("drafts.abandon.no_value"),
- callback: () => resolve(data),
- },
- {
- label: I18n.t("drafts.abandon.yes_value"),
- class: "btn-danger",
- icon: iconHTML("far-trash-alt"),
- callback: () => {
- this.destroyDraft(data.draft_sequence).finally(() => {
- data.draft = null;
- resolve(data);
- });
+ this.dialog.alert({
+ message: I18n.t("drafts.abandon.confirm"),
+ buttons: [
+ {
+ label: I18n.t("drafts.abandon.yes_value"),
+ class: "btn-danger",
+ icon: "far-trash-alt",
+ action: () => {
+ this.destroyDraft(data.draft_sequence).finally(() => {
+ data.draft = null;
+ resolve(data);
+ });
+ },
},
- },
- ]);
+ {
+ label: I18n.t("drafts.abandon.no_value"),
+ class: "btn-resume-editing",
+ action: () => resolve(data),
+ },
+ ],
+ });
});
},
diff --git a/app/assets/javascripts/discourse/app/initializers/logout.js b/app/assets/javascripts/discourse/app/initializers/logout.js
index 2bc7a3822fc..70eb8068da1 100644
--- a/app/assets/javascripts/discourse/app/initializers/logout.js
+++ b/app/assets/javascripts/discourse/app/initializers/logout.js
@@ -1,5 +1,4 @@
import I18n from "I18n";
-import bootbox from "bootbox";
import logout from "discourse/lib/logout";
let _showingLogout = false;
@@ -10,25 +9,27 @@ export default {
after: "message-bus",
initialize(container) {
- const messageBus = container.lookup("service:message-bus");
- messageBus.subscribe("/logout", () => {
- if (_showingLogout) {
- return;
+ const messageBus = container.lookup("service:message-bus"),
+ dialog = container.lookup("service:dialog");
+
+ if (!messageBus) {
+ return;
+ }
+
+ messageBus.subscribe("/logout", function () {
+ if (!_showingLogout) {
+ _showingLogout = true;
+
+ dialog.alert({
+ message: I18n.t("logout"),
+ confirmButtonLabel: "home",
+ didConfirm: logout,
+ didCancel: logout,
+ shouldDisplayCancel: false,
+ });
}
_showingLogout = true;
-
- bootbox.dialog(
- I18n.t("logout"),
- {
- label: I18n.t("home"),
- callback: logout,
- },
- {
- onEscape: logout,
- backdrop: "static",
- }
- );
});
},
};
diff --git a/app/assets/javascripts/discourse/app/models/composer.js b/app/assets/javascripts/discourse/app/models/composer.js
index 9b4854a638c..2c365f47f25 100644
--- a/app/assets/javascripts/discourse/app/models/composer.js
+++ b/app/assets/javascripts/discourse/app/models/composer.js
@@ -18,7 +18,7 @@ import RestModel from "discourse/models/rest";
import Site from "discourse/models/site";
import Topic from "discourse/models/topic";
import User from "discourse/models/user";
-import bootbox from "bootbox";
+import { inject as service } from "@ember/service";
import deprecated from "discourse-common/lib/deprecated";
import { isEmpty } from "@ember/utils";
import { propertyNotEqual } from "discourse/lib/computed";
@@ -119,6 +119,7 @@ export const SAVE_ICONS = {
};
const Composer = RestModel.extend({
+ dialog: service(),
_categoryId: null,
unlistTopic: false,
noBump: false,
@@ -453,7 +454,9 @@ const Composer = RestModel.extend({
const category = this.category;
if (category && category.topic_template) {
if (this.reply.trim() === category.topic_template.trim()) {
- bootbox.alert(I18n.t("composer.error.topic_template_not_modified"));
+ this.dialog.alert(
+ I18n.t("composer.error.topic_template_not_modified")
+ );
return true;
}
}
@@ -1277,28 +1280,23 @@ const Composer = RestModel.extend({
) {
const json = e.jqXHR.responseJSON;
draftStatus = json.errors[0];
- if (json.extras && json.extras.description) {
- const buttons = [];
- // ignore and force save draft
- buttons.push({
- label: I18n.t("composer.ignore"),
- class: "btn",
- callback: () => {
- this.set("draftForceSave", true);
- },
+ if (json.extras?.description) {
+ this.dialog.alert({
+ message: json.extras.description,
+ buttons: [
+ {
+ label: I18n.t("composer.reload"),
+ class: "btn-primary",
+ action: () => window.location.reload(),
+ },
+ {
+ label: I18n.t("composer.ignore"),
+ class: "btn",
+ action: () => this.set("draftForceSave", true),
+ },
+ ],
});
-
- // reload
- buttons.push({
- label: I18n.t("composer.reload"),
- class: "btn btn-primary",
- callback: () => {
- window.location.reload();
- },
- });
-
- bootbox.dialog(json.extras.description, buttons);
}
}
this.setProperties({
diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
index 422b64a7545..7ebab8402c1 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js
@@ -182,9 +182,9 @@ acceptance("Composer", function (needs) {
await fillIn("#reply-title", "this title triggers an error");
await fillIn(".d-editor-input", "this is the *content* of a post");
await click("#reply-control button.create");
- assert.ok(exists(".bootbox.modal"), "it pops up an error message");
- await click(".bootbox.modal a.btn-primary");
- assert.ok(!exists(".bootbox.modal"), "it dismisses the error");
+ assert.ok(exists(".dialog-body"), "it pops up an error message");
+ await click(".dialog-footer .btn-primary");
+ assert.ok(!exists(".dialog-body"), "it dismisses the error");
assert.ok(exists(".d-editor-input"), "the composer input is visible");
});
@@ -223,13 +223,14 @@ acceptance("Composer", function (needs) {
await fillIn("#reply-title", "This title doesn't matter");
await fillIn(".d-editor-input", "custom message");
await click("#reply-control button.create");
+
assert.strictEqual(
- query(".bootbox .modal-body").innerText,
+ query("#dialog-holder .dialog-body").innerText,
"This is a custom response"
);
assert.strictEqual(currentURL(), "/", "it doesn't change routes");
- await click(".bootbox .btn-primary");
+ await click(".dialog-footer .btn-primary");
assert.strictEqual(
currentURL(),
"/faq",
@@ -764,11 +765,11 @@ acceptance("Composer", function (needs) {
await click(".topic-post:nth-of-type(1) button.edit");
assert.strictEqual(
- query(".modal-body").innerText,
+ query(".dialog-body").innerText,
I18n.t("drafts.abandon.confirm")
);
- await click(".modal-footer .btn.btn-default");
+ await click(".dialog-footer .btn-resume-editing");
});
test("Can switch states without abandon popup", async function (assert) {
@@ -826,7 +827,7 @@ acceptance("Composer", function (needs) {
await visit("/u/charlie");
await click("button.compose-pm");
- await click(".modal .btn-default");
+ await click(".dialog-footer .btn-resume-editing");
const privateMessageUsers = selectKit("#private-message-users");
assert.strictEqual(privateMessageUsers.header().value(), "codinghorror");
diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-test.js
index 54711f0aff1..e54642d5fee 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/user-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/user-test.js
@@ -1,3 +1,4 @@
+import I18n from "I18n";
import EmberObject from "@ember/object";
import User from "discourse/models/user";
import selectKit from "discourse/tests/helpers/select-kit-helper";
@@ -6,10 +7,12 @@ import userFixtures from "discourse/tests/fixtures/user-fixtures";
import {
acceptance,
exists,
+ publishToMessageBus,
query,
queryAll,
updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers";
+import * as logout from "discourse/lib/logout";
import { click, currentRouteName, visit } from "@ember/test-helpers";
import { cloneJSON } from "discourse-common/lib/object";
import { test } from "qunit";
@@ -305,3 +308,27 @@ acceptance(
});
}
);
+
+acceptance("User - Logout", function (needs) {
+ needs.user({ username: "eviltrout" });
+
+ test("Dialog works", async function (assert) {
+ sinon.stub(logout, "default");
+ await visit("/u/eviltrout");
+ await publishToMessageBus("/logout");
+
+ assert.ok(exists(".dialog-body"));
+ assert.ok(
+ !exists(".dialog-footer .btn-default"),
+ "no cancel button present"
+ );
+ assert.strictEqual(
+ query(".dialog-footer .btn-primary").innerText,
+ I18n.t("home"),
+ "primary dialog button is present"
+ );
+
+ await click(".dialog-overlay");
+ assert.ok(logout.default.called, "logout helper was called");
+ });
+});
diff --git a/app/assets/stylesheets/common/base/dialog.scss b/app/assets/stylesheets/common/base/dialog.scss
index 566ea39bdec..d5e60bf7c2e 100644
--- a/app/assets/stylesheets/common/base/dialog.scss
+++ b/app/assets/stylesheets/common/base/dialog.scss
@@ -59,6 +59,7 @@
.dialog-close {
margin-left: auto;
+ flex-basis: content;
.d-icon {
color: var(--primary-high);
}
diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss
index e0872b274fe..f067f904989 100644
--- a/app/assets/stylesheets/common/base/modal.scss
+++ b/app/assets/stylesheets/common/base/modal.scss
@@ -278,15 +278,7 @@
}
}
-.bootbox.modal.reply-where-modal {
- max-width: 400px;
- margin-left: -200px;
-
- h1 {
- margin: 0;
- font-size: var(--font-up-2);
- }
-
+.reply-where-modal {
.btn {
display: block;
text-align: left;