Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / mediawiki.confirmCloseWindow.js
bloba3180747413a7df8702c2290f98d85a34f2e95fc
1 ( function () {
2         /**
3          * Prevent the closing of a window with a confirm message (the onbeforeunload event seems to
4          * work in most browsers).
5          *
6          * Provided by the mediawiki.confirmCloseWindow module.
7          *
8          * This supersedes any previous onbeforeunload handler. If there was a handler before, it is
9          * restored when you execute the returned release() function.
10          *
11          * @example
12          * mw.loader.using( 'mediawiki.confirmCloseWindow' ).then(() => {
13          *     var allowCloseWindow = mw.confirmCloseWindow();
14          *     // ... do stuff that can't be interrupted ...
15          *     allowCloseWindow.release();
16          *
17          *    // The second function returned is a trigger function to trigger the check and an alert
18          *    // window manually, e.g.:
19          *
20          *     var allowCloseWindow = mw.confirmCloseWindow();
21          *     // ... do stuff that can't be interrupted ...
22          *     if ( allowCloseWindow.trigger() ) {
23          *         // don't do anything (e.g. destroy the input field)
24          *     } else {
25          *         // do whatever you wanted to do
26          *     }
27          * })
28          * @method confirmCloseWindow
29          * @memberof mw
30          * @param {Object} [options]
31          * @param {string} [options.namespace] Optional jQuery event namespace, to allow loosely coupled
32          *  external code to release your trigger. For example, the VisualEditor extension can use this
33          *  remove the trigger registered by mediawiki.action.edit, without strong runtime coupling.
34          * @param {Function} [options.test]
35          * @param {boolean} [options.test.return=true] Whether to show the dialog to the user.
36          * @return {Object} An object of functions to work with this module
37          */
38         mw.confirmCloseWindow = function ( options ) {
39                 let beforeunloadEvent = 'beforeunload';
40                 const test = options && options.test || function () {
41                         return true;
42                 };
44                 if ( options && options.namespace ) {
45                         beforeunloadEvent += '.' + options.namespace;
46                 }
48                 /**
49                  * @ignore
50                  * @param {Event} e
51                  * @return {string|undefined}
52                  */
53                 function onBeforeunload( e ) {
54                         if ( test() ) {
55                                 // Standard supported in Firefox, IE9+, Safari 11.1+
56                                 e.preventDefault();
58                                 // Support: Chrome, Edge, Safari 9-11
59                                 //
60                                 // Leave the "extra text" string empty since Chrome/Firefox/Safari/Edge
61                                 // won't display it anyway, and because otherwise IE11 would actually
62                                 // still display it otherwise.
63                                 //
64                                 // Before 2015, the standard behaviour was that when a string is returned here,
65                                 // the browser will prompt a native and localised message like
66                                 // "Are you sure? Unsaved changes may be lost.", with the returned string after
67                                 // it on a new line.
68                                 //
69                                 // As of 2015, this is no longer supported in modern browsers. But, the only
70                                 // cross-browser compatible way to trigger the prompt at all, remains to return
71                                 // a string, any string. The HTML spec says e.preventDefault() is the new way to
72                                 // signal this, but Chrome/Edge don't support that yet, and we also support
73                                 // Safari 9-11 which didn't have it.
74                                 //
75                                 // <https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event>
76                                 return '';
77                         }
78                 }
80                 $( window ).on( beforeunloadEvent, onBeforeunload );
82                 return {
83                         /**
84                          * Remove the event listener and don't show an alert anymore, if the user wants to leave
85                          * the page.
86                          *
87                          * @ignore
88                          */
89                         release: function () {
90                                 $( window ).off( beforeunloadEvent, onBeforeunload );
91                         },
92                         /**
93                          * Trigger the module's function manually.
94                          *
95                          * Check, if options.test() returns true and show an alert to the user if he/she want
96                          * to leave this page. Returns false, if options.test() returns false or the user
97                          * cancelled the alert window (~don't leave the page), true otherwise.
98                          *
99                          * @ignore
100                          * @return {boolean}
101                          */
102                         trigger: function () {
103                                 const message = mw.msg( 'confirmleave-warning' );
104                                 // use confirm to show the message to the user (if options.text() is true)
105                                 // eslint-disable-next-line no-alert
106                                 if ( test() && !confirm( message ) ) {
107                                         // the user want to keep the actual page
108                                         return false;
109                                 }
110                                 // otherwise return true
111                                 return true;
112                         }
113                 };
114         };
115 }() );