-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Service to show confirmation prompt when leaving a dirty form (#16688)
* Service to show confirmation prompt when leaving a dirty form * Add data test subject for breadcrumbs This will enable testing the dirty prompt service via functional tests by providing a means for the user to navigate away via the breadcrumbs
- Loading branch information
1 parent
0ca6b55
commit d250e66
Showing
4 changed files
with
93 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { uiModules } from 'ui/modules'; | ||
import { DirtyPrompt } from './dirty_prompt'; | ||
|
||
uiModules.get('kibana') | ||
.factory('dirtyPrompt', ($injector) => { | ||
const $window = $injector.get('$window'); | ||
const confirmModal = $injector.get('confirmModal'); | ||
const $rootScope = $injector.get('$rootScope'); | ||
|
||
return new DirtyPrompt($window, $rootScope, confirmModal); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { noop } from 'lodash'; | ||
|
||
const confirmMessage = `You have unsaved changes. Proceed and discard changes?`; | ||
|
||
function registerUrlChangeHandler(checkDirty) { | ||
this.beforeUnloadHandler = (event) => { | ||
if (checkDirty()) { | ||
// Browsers do not honor the message you set here. The only requirement | ||
// is that is is not an empty string. I am just using the confirmMessage | ||
// here for consistency | ||
event.returnValue = confirmMessage; | ||
} | ||
}; | ||
|
||
// When the user navigates to an external url or another app, we must | ||
// rely on the build-in beforeunload confirmation dialog. We do not have | ||
// the ability to change the text or appearance of this dialog. | ||
this.$window.addEventListener('beforeunload', this.beforeUnloadHandler); | ||
} | ||
|
||
function deregisterUrlChangeHandler() { | ||
this.$window.removeEventListener('beforeunload', this.beforeUnloadHandler); | ||
} | ||
|
||
function registerRouteChangeHandler(checkDirty) { | ||
// When the user navigates within the same app, we can present them with | ||
// a friendly confirmation dialog box | ||
const deregister = this.$rootScope.$on('$locationChangeStart', (event, newUrl) => { | ||
if (!checkDirty()) { | ||
return; | ||
} | ||
|
||
// At this point, we know the dirty prompt should be shown, so | ||
// cancel the location change event, and keep the user at | ||
// their current location | ||
event.preventDefault(); | ||
|
||
// Notify user about unsaved changes and ask the user for confirmation | ||
// about navigating away (changing their location) anyway | ||
const confirmModalOptions = { | ||
onConfirm: () => { | ||
this.deregister(); | ||
this.$window.location.href = newUrl; | ||
}, | ||
confirmButtonText: 'Discard Changes' | ||
}; | ||
|
||
return this.confirmModal(confirmMessage, confirmModalOptions); | ||
}); | ||
|
||
this.deregisterListener = deregister; | ||
} | ||
|
||
function deregisterRouteChangeHandler() { | ||
this.deregisterListener(); | ||
} | ||
|
||
export class DirtyPrompt { | ||
constructor($window, $rootScope, confirmModal) { | ||
this.$window = $window; | ||
this.$rootScope = $rootScope; | ||
this.confirmModal = confirmModal; | ||
this.deregisterListener = noop; | ||
this.beforeUnloadHandler = noop; | ||
} | ||
|
||
/** | ||
* @param checkDirty function which returns a bool to call to | ||
* determine dirty state | ||
*/ | ||
register = (checkDirty) => { | ||
registerUrlChangeHandler.call(this, checkDirty); | ||
registerRouteChangeHandler.call(this, checkDirty); | ||
} | ||
|
||
deregister = () => { | ||
deregisterUrlChangeHandler.call(this); | ||
deregisterRouteChangeHandler.call(this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './dirty_prompt.factory'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters