From df003eaf7bbfa2d5e44db4ba48b9111a82cde071 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 12 Nov 2020 19:13:52 +0530 Subject: [PATCH] FIX: add a way to cancel initialization of new draft (#11106) --- .../discourse/app/controllers/composer.js | 57 ++++++++----------- .../app/controllers/discard-draft.js | 40 +++++++++++++ .../app/templates/modal/discard-draft.hbs | 10 ++++ .../tests/acceptance/composer-test.js | 36 ++++++++---- config/locales/client.en.yml | 1 + 5 files changed, 99 insertions(+), 45 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/controllers/discard-draft.js create mode 100644 app/assets/javascripts/discourse/app/templates/modal/discard-draft.hbs diff --git a/app/assets/javascripts/discourse/app/controllers/composer.js b/app/assets/javascripts/discourse/app/controllers/composer.js index cb24c87a7ee..316faee0d69 100644 --- a/app/assets/javascripts/discourse/app/controllers/composer.js +++ b/app/assets/javascripts/discourse/app/controllers/composer.js @@ -28,6 +28,7 @@ import { isTesting } from "discourse-common/config/environment"; import EmberObject, { computed, action } from "@ember/object"; import deprecated from "discourse-common/lib/deprecated"; import bootbox from "bootbox"; +import showModal from "discourse/lib/show-modal"; import { cannotPostAgain, durationTextFromSeconds, @@ -1097,46 +1098,36 @@ export default Controller.extend({ cancel(this._saveDraftDebounce); } - const keyPrefix = - this.model.action === "edit" ? "post.abandon_edit" : "post.abandon"; - let promise = new Promise((resolve, reject) => { if (this.get("model.hasMetaData") || this.get("model.replyDirty")) { - bootbox.dialog(I18n.t(keyPrefix + ".confirm"), [ - { - label: differentDraft - ? I18n.t(keyPrefix + ".no_save_draft") - : I18n.t(keyPrefix + ".no_value"), - callback: () => { - // cancel composer without destroying draft on new draft context - if (differentDraft) { + const controller = showModal("discard-draft", { + model: this.model, + modalClass: "discard-draft-modal", + title: "post.abandon.title", + }); + controller.setProperties({ + differentDraft, + onDestroyDraft: () => { + this.destroyDraft() + .then(() => { this.model.clearState(); this.close(); + }) + .finally(() => { resolve(); - } + }); + }, + onSaveDraft: () => { + // cancel composer without destroying draft on new draft context + if (differentDraft) { + this.model.clearState(); + this.close(); + resolve(); + } - reject(); - }, + reject(); }, - { - label: I18n.t(keyPrefix + ".yes_value"), - class: "btn-danger", - callback: (result) => { - if (result) { - this.destroyDraft() - .then(() => { - this.model.clearState(); - this.close(); - }) - .finally(() => { - resolve(); - }); - } else { - resolve(); - } - }, - }, - ]); + }); } else { // it is possible there is some sort of crazy draft with no body ... just give up on it this.destroyDraft() diff --git a/app/assets/javascripts/discourse/app/controllers/discard-draft.js b/app/assets/javascripts/discourse/app/controllers/discard-draft.js new file mode 100644 index 00000000000..32633aec29d --- /dev/null +++ b/app/assets/javascripts/discourse/app/controllers/discard-draft.js @@ -0,0 +1,40 @@ +import Controller from "@ember/controller"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default Controller.extend(ModalFunctionality, { + differentDraft: null, + + @discourseComputed() + keyPrefix() { + return this.model.action === "edit" ? "post.abandon_edit" : "post.abandon"; + }, + + @discourseComputed("keyPrefix") + descriptionKey(keyPrefix) { + return `${keyPrefix}.confirm`; + }, + + @discourseComputed("keyPrefix") + discardKey(keyPrefix) { + return `${keyPrefix}.yes_value`; + }, + + @discourseComputed("keyPrefix", "differentDraft") + saveKey(keyPrefix, differentDraft) { + return differentDraft + ? `${keyPrefix}.no_save_draft` + : `${keyPrefix}.no_value`; + }, + + actions: { + _destroyDraft() { + this.onDestroyDraft(); + this.send("closeModal"); + }, + _saveDraft() { + this.onSaveDraft(); + this.send("closeModal"); + }, + }, +}); diff --git a/app/assets/javascripts/discourse/app/templates/modal/discard-draft.hbs b/app/assets/javascripts/discourse/app/templates/modal/discard-draft.hbs new file mode 100644 index 00000000000..37720352a11 --- /dev/null +++ b/app/assets/javascripts/discourse/app/templates/modal/discard-draft.hbs @@ -0,0 +1,10 @@ +{{#d-modal-body}} +
+ {{i18n descriptionKey}} +
+{{/d-modal-body}} + + diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js index a86dd87cbd4..08277cfa32b 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-test.js @@ -291,9 +291,9 @@ acceptance("Composer", function (needs) { await click(".topic-post:eq(0) button.show-more-actions"); await click(".topic-post:eq(0) button.edit"); - await click("a[data-handler='0']"); + await click(".modal-footer button:eq(1)"); - assert.ok(!visible(".bootbox.modal")); + assert.ok(!visible(".discard-draft-modal.modal")); assert.equal( queryAll(".d-editor-input").val(), "this is the content of my reply" @@ -408,9 +408,12 @@ acceptance("Composer", function (needs) { await click(".topic-post:eq(0) button.edit"); await fillIn(".d-editor-input", "This is a dirty reply"); await click(".topic-post:eq(1) button.edit"); - assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog"); + assert.ok( + exists(".discard-draft-modal.modal"), + "it pops up a confirmation dialog" + ); - await click(".modal-footer a:eq(0)"); + await click(".modal-footer button:eq(0)"); assert.equal( queryAll(".d-editor-input").val().indexOf("This is the second post."), 0, @@ -563,8 +566,11 @@ acceptance("Composer", function (needs) { await click(".topic-post:eq(0) button.reply"); await fillIn(".d-editor-input", "This is a dirty reply"); await click(".topic-post:eq(0) button.edit"); - assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog"); - await click(".modal-footer a:eq(0)"); + assert.ok( + exists(".discard-draft-modal.modal"), + "it pops up a confirmation dialog" + ); + await click(".modal-footer button:eq(0)"); assert.equal( queryAll(".d-editor-input").val().indexOf("This is the first post."), 0, @@ -579,12 +585,15 @@ acceptance("Composer", function (needs) { await fillIn(".d-editor-input", "This is a dirty reply"); await click(".toggler"); await click(".topic-post:eq(1) button.edit"); - assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog"); + assert.ok( + exists(".discard-draft-modal.modal"), + "it pops up a confirmation dialog" + ); assert.equal( - queryAll(".modal-footer a:eq(1)").text(), + queryAll(".modal-footer button:eq(1)").text().trim(), I18n.t("post.abandon.no_value") ); - await click(".modal-footer a:eq(0)"); + await click(".modal-footer button:eq(0)"); assert.equal( queryAll(".d-editor-input").val().indexOf("This is the second post."), 0, @@ -601,12 +610,15 @@ acceptance("Composer", function (needs) { await click("#site-logo"); await click("#create-topic"); - assert.ok(exists(".bootbox.modal"), "it pops up a confirmation dialog"); + assert.ok( + exists(".discard-draft-modal.modal"), + "it pops up a confirmation dialog" + ); assert.equal( - queryAll(".modal-footer a:eq(1)").text(), + queryAll(".modal-footer button:eq(1)").text().trim(), I18n.t("post.abandon.no_save_draft") ); - await click(".modal-footer a:eq(1)"); + await click(".modal-footer button:eq(1)"); assert.equal( queryAll(".d-editor-input").val(), "", diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 4b224485814..feeb69b08f4 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2762,6 +2762,7 @@ en: yes_value: "Yes, discard edit" abandon: + title: "Abandon Draft" confirm: "Are you sure you want to abandon your post?" no_value: "No, keep" no_save_draft: "No, save draft"