Merge "resources: Strip '$' and 'mw' from file closures"
[lhc/web/wiklou.git] / resources / src / mediawiki.confirmCloseWindow.js
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 * This supersedes any previous onbeforeunload handler. If there was a handler before, it is
7 * restored when you execute the returned release() function.
8 *
9 * var allowCloseWindow = mw.confirmCloseWindow();
10 * // ... do stuff that can't be interrupted ...
11 * allowCloseWindow.release();
12 *
13 * The second function returned is a trigger function to trigger the check and an alert
14 * window manually, e.g.:
15 *
16 * var allowCloseWindow = mw.confirmCloseWindow();
17 * // ... do stuff that can't be interrupted ...
18 * if ( allowCloseWindow.trigger() ) {
19 * // don't do anything (e.g. destroy the input field)
20 * } else {
21 * // do whatever you wanted to do
22 * }
23 *
24 * @method confirmCloseWindow
25 * @member mw
26 * @param {Object} [options]
27 * @param {string} [options.namespace] Namespace for the event registration
28 * @param {string} [options.message]
29 * @param {string} options.message.return The string message to show in the confirm dialog.
30 * @param {Function} [options.test]
31 * @param {boolean} [options.test.return=true] Whether to show the dialog to the user.
32 * @return {Object} An object of functions to work with this module
33 */
34 mw.confirmCloseWindow = function ( options ) {
35 var savedUnloadHandler,
36 mainEventName = 'beforeunload',
37 showEventName = 'pageshow',
38 message;
39
40 options = $.extend( {
41 message: mw.message( 'mwe-prevent-close' ).text(),
42 test: function () { return true; }
43 }, options );
44
45 if ( options.namespace ) {
46 mainEventName += '.' + options.namespace;
47 showEventName += '.' + options.namespace;
48 }
49
50 if ( typeof options.message === 'function' ) {
51 message = options.message();
52 } else {
53 message = options.message;
54 }
55
56 $( window ).on( mainEventName, function () {
57 if ( options.test() ) {
58 // remove the handler while the alert is showing - otherwise breaks caching in Firefox (3?).
59 // but if they continue working on this page, immediately re-register this handler
60 savedUnloadHandler = window.onbeforeunload;
61 window.onbeforeunload = null;
62 setTimeout( function () {
63 window.onbeforeunload = savedUnloadHandler;
64 }, 1 );
65
66 // show an alert with this message
67 return message;
68 }
69 } ).on( showEventName, function () {
70 // Re-add onbeforeunload handler
71 if ( !window.onbeforeunload && savedUnloadHandler ) {
72 window.onbeforeunload = savedUnloadHandler;
73 }
74 } );
75
76 /**
77 * Return the object with functions to release and manually trigger the confirm alert
78 *
79 * @ignore
80 */
81 return {
82 /**
83 * Remove all event listeners and don't show an alert anymore, if the user wants to leave
84 * the page.
85 *
86 * @ignore
87 */
88 release: function () {
89 $( window ).off( mainEventName + ' ' + showEventName );
90 },
91 /**
92 * Trigger the module's function manually: Check, if options.test() returns true and show
93 * an alert to the user if he/she want to leave this page. Returns false, if options.test() returns
94 * false or the user cancelled the alert window (~don't leave the page), true otherwise.
95 *
96 * @ignore
97 * @return {boolean}
98 */
99 trigger: function () {
100 // use confirm to show the message to the user (if options.text() is true)
101 // eslint-disable-next-line no-alert
102 if ( options.test() && !confirm( message ) ) {
103 // the user want to keep the actual page
104 return false;
105 }
106 // otherwise return true
107 return true;
108 }
109 };
110 };
111 }() );