Refactored leave-editor confirmation modal

refs https://github.com/TryGhost/Team/issues/559

- switched to new ember-promise-modals pattern
- simplified `willTransition` handling because we can now wait on the promise returned from opening the modal
  - the modal content was changed to use `{{on "click" (fn @close true)}}` on the "leave" button so we can check for that return value for leave confirmation
This commit is contained in:
Kevin Ansfield 2022-01-12 10:16:39 +00:00
parent 97c9c23d4a
commit 6a43cb27c3
5 changed files with 61 additions and 95 deletions

View File

@ -1,18 +0,0 @@
<header class="modal-header">
<h1>Are you sure you want to leave this page?</h1>
</header>
<a class="close" href="" role="button" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>
<div class="modal-body">
<p>
Hey there! It looks like you're in the middle of writing something and
you haven't saved all of your content.
</p>
<p>Save before you go!</p>
</div>
<div class="modal-footer">
<button {{action "closeModal"}} class="gh-btn"><span>Stay</span></button>
<button {{action "confirm"}} class="gh-btn gh-btn-red"><span>Leave</span></button>
</div>

View File

@ -1,14 +0,0 @@
import ModalComponent from 'ghost-admin/components/modal-base';
import RSVP from 'rsvp';
export default ModalComponent.extend({
actions: {
confirm() {
this.confirm();
this.send('closeModal');
}
},
// Allowed actions
confirm: () => RSVP.resolve()
});

View File

@ -0,0 +1,21 @@
<div class="modal-content">
<header class="modal-header">
<h1>Are you sure you want to leave this page?</h1>
</header>
<button class="close" title="Close" type="button" {{on "click" @close}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body">
<p>
Hey there! It looks like you're in the middle of writing something and
you haven't saved all of your content.
</p>
<p>Save before you go!</p>
</div>
<div class="modal-footer">
<button class="gh-btn" {{on "click" @close}}><span>Stay</span></button>
<button class="gh-btn gh-btn-red" {{on "click" (fn @close true)}}><span>Leave</span></button>
</div>
</div>

View File

@ -105,9 +105,7 @@ export default Controller.extend({
/* public properties -----------------------------------------------------*/
leaveEditorTransition: null,
shouldFocusTitle: false,
showLeaveEditorModal: false,
showReAuthenticateModal: false,
showEmailPreviewModal: false,
showPostPreviewModal: false,
@ -120,8 +118,8 @@ export default Controller.extend({
/* private properties ----------------------------------------------------*/
// set by setPost and _postSaved, used in hasDirtyAttributes
_previousTagNames: null,
_leaveConfirmed: false,
_previousTagNames: null, // set by setPost and _postSaved, used in hasDirtyAttributes
/* computed properties ---------------------------------------------------*/
@ -220,46 +218,6 @@ export default Controller.extend({
this._timedSaveTask.cancelAll();
},
toggleLeaveEditorModal(transition) {
let leaveTransition = this.leaveEditorTransition;
// "cancel" was clicked in the "are you sure?" modal so we just
// reset the saved transition and remove the modal
if (!transition && this.showLeaveEditorModal) {
this.set('leaveEditorTransition', null);
this.set('showLeaveEditorModal', false);
return;
}
if (!leaveTransition || transition.targetName === leaveTransition.targetName) {
this.set('leaveEditorTransition', transition);
// if a save is running, wait for it to finish then transition
if (this.get('saveTasks.isRunning')) {
return this.get('saveTasks.last').then(() => {
transition.retry();
});
}
// if an autosave is scheduled, cancel it, save then transition
if (this._autosaveRunning) {
this.send('cancelAutosave');
this.autosaveTask.cancelAll();
return this.autosaveTask.perform().then(() => {
transition.retry();
});
}
// we genuinely have unsaved data, show the modal
if (this.post) {
Object.assign(this._leaveModalReason, {status: this.post.status});
}
console.log('showing leave editor modal', this._leaveModalReason); // eslint-disable-line
this.set('showLeaveEditorModal', true);
}
},
// called by the "are you sure?" modal
leaveEditor() {
let transition = this.leaveEditorTransition;
@ -825,14 +783,13 @@ export default Controller.extend({
},
// called by editor route's willTransition hook, fires for editor.new->edit,
// editor.edit->edit, or editor->any. Triggers `toggleLeaveEditorModal` action
// which will either finish autosave then retry transition or abort and show
// the "are you sure?" modal
willTransition(transition) {
// editor.edit->edit, or editor->any. Will either finish autosave then retry
// transition or abort and show the "are you sure want to leave?" modal
async willTransition(transition) {
let post = this.post;
// exit early and allow transition if we have no post, occurs if reset
// has already been called as in the `leaveEditor` action
// has already been called
if (!post) {
return;
}
@ -848,21 +805,49 @@ export default Controller.extend({
let hasDirtyAttributes = this.hasDirtyAttributes;
let state = post.getProperties('isDeleted', 'isSaving', 'hasDirtyAttributes', 'isNew');
let fromNewToEdit = this.get('router.currentRouteName') === 'editor.new'
let fromNewToEdit = this.router.currentRouteName === 'editor.new'
&& transition.targetName === 'editor.edit'
&& transition.intent.contexts
&& transition.intent.contexts[0]
&& transition.intent.contexts[0].id === post.get('id');
&& transition.intent.contexts[0].id === post.id;
let deletedWithoutChanges = state.isDeleted
&& (state.isSaving || !state.hasDirtyAttributes);
// controller is dirty and we aren't in a new->edit or delete->index
// transition so show our "are you sure you want to leave?" modal
if (!fromNewToEdit && !deletedWithoutChanges && hasDirtyAttributes) {
if (!this._leaveConfirmed && !fromNewToEdit && !deletedWithoutChanges && hasDirtyAttributes) {
transition.abort();
this.send('toggleLeaveEditorModal', transition);
return;
// if a save is running, wait for it to finish then transition
if (this.saveTasks.isRunning) {
await this.saveTasks.last;
return transition.retry();
}
// if an autosave is scheduled, cancel it, save then transition
if (this._autosaveRunning) {
this.send('cancelAutosave');
this.autosaveTask.cancelAll();
await this.autosaveTask.perform();
return transition.retry();
}
// we genuinely have unsaved data, show the modal
if (this.post) {
Object.assign(this._leaveModalReason, {status: this.post.status});
}
console.log('showing leave editor modal', this._leaveModalReason); // eslint-disable-line
const reallyLeave = await this.modals.open('modals/editor/confirm-leave');
if (reallyLeave !== true) {
return;
} else {
this._leaveConfirmed = true;
transition.retry();
}
}
// the transition is now certain to complete so cleanup and reset if
@ -894,12 +879,11 @@ export default Controller.extend({
}
this._previousTagNames = [];
this._leaveConfirmed = false;
this.set('post', null);
this.set('hasDirtyAttributes', false);
this.set('shouldFocusTitle', false);
this.set('leaveEditorTransition', null);
this.set('showLeaveEditorModal', false);
this.set('showPostPreviewModal', false);
this.set('showSettingsMenu', false);
this.set('wordCount', null);

View File

@ -123,13 +123,6 @@
{{/if}}
</button>
{{#if this.showLeaveEditorModal}}
<GhFullscreenModal @modal="leave-editor"
@confirm={{action "leaveEditor"}}
@close={{action "toggleLeaveEditorModal"}}
@modifier="action wide" />
{{/if}}
{{#if this.showReAuthenticateModal}}
<GhFullscreenModal @modal="re-authenticate"
@close={{action "toggleReAuthenticateModal"}}