Implement mediawiki.confirmCloseWindow module
authorMark Holmquist <mtraceur@member.fsf.org>
Fri, 1 Aug 2014 18:05:09 +0000 (11:05 -0700)
committerKrinkle <krinklemail@gmail.com>
Tue, 23 Sep 2014 03:32:50 +0000 (03:32 +0000)
Copied from UploadWizard, removed there in I9411a6d33.

Change-Id: I5d35b6fddd73cf56371eeda299ee0779cb40397a

resources/Resources.php
resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
resources/src/mediawiki/mediawiki.confirmCloseWindow.js [new file with mode: 0644]

index c634d9d..a82260c 100644 (file)
@@ -818,6 +818,11 @@ return array(
        'mediawiki.content.json' => array(
                'styles' => 'resources/src/mediawiki/mediawiki.content.json.css',
        ),
+       'mediawiki.confirmCloseWindow' => array(
+               'scripts' => array(
+                       'resources/src/mediawiki/mediawiki.confirmCloseWindow.js',
+               ),
+       ),
        'mediawiki.debug' => array(
                'scripts' => array(
                        'resources/src/mediawiki/mediawiki.debug.js',
@@ -1079,7 +1084,8 @@ return array(
                'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js',
                'dependencies' => array(
                        'jquery.textSelection',
-                       'mediawiki.jqueryMsg'
+                       'mediawiki.jqueryMsg',
+                       'mediawiki.confirmCloseWindow',
                ),
                'messages' => array(
                        'editwarning-warning',
index b565440..6b33012 100644 (file)
@@ -5,54 +5,37 @@
        'use strict';
 
        $( function () {
-               var savedWindowOnBeforeUnload,
-                       $wpTextbox1 = $( '#wpTextbox1' ),
-                       $wpSummary = $( '#wpSummary' );
+               var allowCloseWindow,
+                       $textBox = $( '#wpTextbox1' ),
+                       $summary = $( '#wpSummary' ),
+                       $both = $textBox.add( $summary );
+
                // Check if EditWarning is enabled and if we need it
-               if ( $wpTextbox1.length === 0 ) {
+               if ( !mw.user.options.get( 'useeditwarning' ) ) {
                        return true;
                }
-               // Get the original values of some form elements
-               $wpTextbox1.add( $wpSummary ).each( function () {
-                       $( this ).data( 'origtext', $( this ).val() );
+
+               // Save the original value of the text fields
+               $both.each( function ( index, element ) {
+                       var $element = $( element );
+                       $element.data( 'origtext', $element.textSelection( 'getContents' ) );
                } );
-               $( window )
-                       .on( 'beforeunload.editwarning', function () {
-                               var retval;
 
-                               // Check if the current values of some form elements are the same as
-                               // the original values
-                               if (
-                                       mw.config.get( 'wgAction' ) === 'submit' ||
-                                               $wpTextbox1.data( 'origtext' ) !== $wpTextbox1.textSelection( 'getContents' ) ||
-                                               $wpSummary.data( 'origtext' ) !== $wpSummary.textSelection( 'getContents' )
-                               ) {
-                                       // Return our message
-                                       retval = mw.msg( 'editwarning-warning' );
-                               }
+               allowCloseWindow = mw.confirmCloseWindow( {
+                       test: function () {
+                               // We use .textSelection, because editors might not have updated the form yet.
+                               return mw.config.get( 'wgAction' ) === 'submit' ||
+                                       $textBox.data( 'origtext' ) !== $textBox.textSelection( 'getContents' ) ||
+                                       $summary.data( 'origtext' ) !== $summary.textSelection( 'getContents' );
+                       },
 
-                               // Unset the onbeforeunload handler so we don't break page caching in Firefox
-                               savedWindowOnBeforeUnload = window.onbeforeunload;
-                               window.onbeforeunload = null;
-                               if ( retval !== undefined ) {
-                                       // ...but if the user chooses not to leave the page, we need to rebind it
-                                       setTimeout( function () {
-                                               window.onbeforeunload = savedWindowOnBeforeUnload;
-                                       }, 1 );
-                                       return retval;
-                               }
-                       } )
-                       .on( 'pageshow.editwarning', function () {
-                               // Re-add onbeforeunload handler
-                               if ( !window.onbeforeunload ) {
-                                       window.onbeforeunload = savedWindowOnBeforeUnload;
-                               }
-                       } );
+                       message: mw.msg( 'editwarning-warning' ),
+                       namespace: 'editwarning'
+               } );
 
                // Add form submission handler
                $( '#editform' ).submit( function () {
-                       // Unbind our handlers
-                       $( window ).off( '.editwarning' );
+                       allowCloseWindow();
                } );
        } );
 
diff --git a/resources/src/mediawiki/mediawiki.confirmCloseWindow.js b/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
new file mode 100644 (file)
index 0000000..177367d
--- /dev/null
@@ -0,0 +1,64 @@
+( function ( mw, $ ) {
+       /**
+        * @method confirmCloseWindow
+        * @member mw
+        *
+        * Prevent the closing of a window with a confirm message (the onbeforeunload event seems to
+        * work in most browsers.)
+        *
+        * This supersedes any previous onbeforeunload handler. If there was a handler before, it is
+        * restored when you execute the returned function.
+        *
+        *     var allowCloseWindow = mw.confirmCloseWindow();
+        *     // ... do stuff that can't be interrupted ...
+        *     allowCloseWindow();
+        *
+        * @param {Object} [options]
+        * @param {string} [options.namespace] Namespace for the event registration
+        * @param {string} [options.message]
+        * @param {string} options.message.return The string message to show in the confirm dialog.
+        * @param {Function} [options.test]
+        * @param {boolean} [options.test.return=true] Whether to show the dialog to the user.
+        * @return {Function} Execute this when you want to allow the user to close the window
+        */
+       mw.confirmCloseWindow = function ( options ) {
+               var savedUnloadHandler,
+                       mainEventName = 'beforeunload',
+                       showEventName = 'pageshow';
+
+               options = $.extend( {
+                       message: mw.message( 'mwe-prevent-close' ).text(),
+                       test: function () { return true; }
+               }, options );
+
+               if ( options.namespace ) {
+                       mainEventName += '.' + options.namespace;
+                       showEventName += '.' + options.namespace;
+               }
+
+               $( window ).on( mainEventName, function () {
+                       if ( options.test() ) {
+                               // remove the handler while the alert is showing - otherwise breaks caching in Firefox (3?).
+                               // but if they continue working on this page, immediately re-register this handler
+                               savedUnloadHandler = window.onbeforeunload;
+                               window.onbeforeunload = null;
+                               setTimeout( function () {
+                                       window.onbeforeunload = savedUnloadHandler;
+                               }, 1 );
+
+                               // show an alert with this message
+                               return options.message;
+                       }
+               } ).on( showEventName, function () {
+                       // Re-add onbeforeunload handler
+                       if ( !window.onbeforeunload && savedUnloadHandler ) {
+                               window.onbeforeunload = savedUnloadHandler;
+                       }
+               } );
+
+               // return the function they can use to stop this
+               return function () {
+                       $( window ).off( mainEventName + ' ' + showEventName );
+               };
+       };
+} )( mediaWiki, jQuery );