mediawiki.notification: Move files to their own directory
authorTimo Tijhof <krinklemail@gmail.com>
Wed, 9 May 2018 17:01:59 +0000 (18:01 +0100)
committerJforrester <jforrester@wikimedia.org>
Wed, 9 May 2018 17:31:07 +0000 (17:31 +0000)
* Reduce clutter in src/mediawiki/.
* Make it easier to see from the repo structure which files
  belong to this module, and which files not. For example,
  'mediawiki.notification.convertmessagebox' and 'mediawiki.notify' are
  logically related, but not actually part of this 4-file module.

Bug: T193826
Change-Id: I274323dffa8af1d046beb21d88f633f432a6ebbc

jsduck.json
resources/Resources.php
resources/src/mediawiki.notification/common.css [new file with mode: 0644]
resources/src/mediawiki.notification/default.css [new file with mode: 0644]
resources/src/mediawiki.notification/notification.js [new file with mode: 0644]
resources/src/mediawiki.notification/print.css [new file with mode: 0644]
resources/src/mediawiki/mediawiki.notification.common.css [deleted file]
resources/src/mediawiki/mediawiki.notification.css [deleted file]
resources/src/mediawiki/mediawiki.notification.js [deleted file]
resources/src/mediawiki/mediawiki.notification.print.css [deleted file]

index 6fb4544..78a1be9 100644 (file)
@@ -16,6 +16,7 @@
                "resources/src/mediawiki.action",
                "resources/src/mediawiki.language",
                "resources/src/mediawiki.messagePoster",
+               "resources/src/mediawiki.notification",
                "resources/src/mediawiki.rcfilters",
                "resources/src/mediawiki.special",
                "resources/src/mediawiki.toolbar",
index e8a5e24..97f35e1 100644 (file)
@@ -1157,14 +1157,14 @@ return [
        ],
        'mediawiki.notification' => [
                'styles' => [
-                       'resources/src/mediawiki/mediawiki.notification.common.css',
-                       'resources/src/mediawiki/mediawiki.notification.print.css'
+                       'resources/src/mediawiki.notification/common.css',
+                       'resources/src/mediawiki.notification/print.css'
                                => [ 'media' => 'print' ],
                ],
                'skinStyles' => [
-                       'default' => 'resources/src/mediawiki/mediawiki.notification.css',
+                       'default' => 'resources/src/mediawiki.notification/default.css',
                ],
-               'scripts' => 'resources/src/mediawiki/mediawiki.notification.js',
+               'scripts' => 'resources/src/mediawiki.notification/notification.js',
                'dependencies' => [
                        'mediawiki.util',
                        'mediawiki.visibleTimeout',
diff --git a/resources/src/mediawiki.notification/common.css b/resources/src/mediawiki.notification/common.css
new file mode 100644 (file)
index 0000000..a1309c2
--- /dev/null
@@ -0,0 +1,7 @@
+.mw-notification-area {
+       position: absolute;
+}
+
+.mw-notification-area-floating {
+       position: fixed;
+}
diff --git a/resources/src/mediawiki.notification/default.css b/resources/src/mediawiki.notification/default.css
new file mode 100644 (file)
index 0000000..a56be76
--- /dev/null
@@ -0,0 +1,53 @@
+.mw-notification-area {
+       top: 0;
+       right: 0;
+       /* Padding on all sides so drop shadows aren't cut by overflow: hidden */
+       padding: 1em;
+       width: 20em;
+       line-height: 1.35;
+       z-index: 10000;
+       /* Avoid horizontal scrollbar on fade in and on fade out */
+       overflow: hidden;
+}
+
+.mw-notification {
+       padding: 0.75em 1.5em;
+       margin-bottom: 0.5em;
+       border: solid 1px #ddd;
+       background-color: #fff;
+       /* Click handler in mediawiki.notification.js */
+       cursor: pointer;
+
+       opacity: 0;
+       -webkit-transform: translateX( 35px );
+       transform: translateX( 35px );
+       -webkit-transition: opacity 0.35s ease-in-out, -webkit-transform 0.35s ease-in-out;
+       transition: opacity 0.35s ease-in-out, transform 0.35s ease-in-out;
+}
+
+.mw-notification-visible {
+       opacity: 1;
+       -webkit-transform: translateX( 0 );
+       transform: translateX( 0 );
+}
+
+.mw-notification-replaced {
+       opacity: 0;
+       -webkit-transform: translateY( -35px );
+       transform: translateY( -35px );
+       pointer-events: none;
+}
+
+.mw-notification-title {
+       font-weight: bold;
+}
+
+.mw-notification.mw-notification-type-warn {
+       border-color: #f5be00; /* yellow */
+       background-color: #ffffe8;
+}
+
+.mw-notification.mw-notification-type-error {
+       border-color: #eb3941; /* red */
+       background-color: #fff8f8;
+}
diff --git a/resources/src/mediawiki.notification/notification.js b/resources/src/mediawiki.notification/notification.js
new file mode 100644 (file)
index 0000000..aa86a4b
--- /dev/null
@@ -0,0 +1,462 @@
+( function ( mw, $ ) {
+       'use strict';
+
+       var notification,
+               // The #mw-notification-area div that all notifications are contained inside.
+               $area,
+               // Number of open notification boxes at any time
+               openNotificationCount = 0,
+               isPageReady = false,
+               preReadyNotifQueue = [],
+               rAF = window.requestAnimationFrame || setTimeout;
+
+       /**
+        * A Notification object for 1 message.
+        *
+        * The underscore in the name is to avoid a bug <https://github.com/senchalabs/jsduck/issues/304>.
+        * It is not part of the actual class name.
+        *
+        * The constructor is not publicly accessible; use mw.notification#notify instead.
+        * This does not insert anything into the document (see #start).
+        *
+        * @class mw.Notification_
+        * @alternateClassName mw.Notification
+        * @constructor
+        * @private
+        * @param {mw.Message|jQuery|HTMLElement|string} message
+        * @param {Object} options
+        */
+       function Notification( message, options ) {
+               var $notification, $notificationContent;
+
+               $notification = $( '<div class="mw-notification"></div>' )
+                       .data( 'mw.notification', this )
+                       .addClass( options.autoHide ? 'mw-notification-autohide' : 'mw-notification-noautohide' );
+
+               if ( options.tag ) {
+                       // Sanitize options.tag before it is used by any code. (Including Notification class methods)
+                       options.tag = options.tag.replace( /[ _-]+/g, '-' ).replace( /[^-a-z0-9]+/ig, '' );
+                       if ( options.tag ) {
+                               $notification.addClass( 'mw-notification-tag-' + options.tag );
+                       } else {
+                               delete options.tag;
+                       }
+               }
+
+               if ( options.type ) {
+                       // Sanitize options.type
+                       options.type = options.type.replace( /[ _-]+/g, '-' ).replace( /[^-a-z0-9]+/ig, '' );
+                       $notification.addClass( 'mw-notification-type-' + options.type );
+               }
+
+               if ( options.title ) {
+                       $( '<div class="mw-notification-title"></div>' )
+                               .text( options.title )
+                               .appendTo( $notification );
+               }
+
+               $notificationContent = $( '<div class="mw-notification-content"></div>' );
+
+               if ( typeof message === 'object' ) {
+                       // Handle mw.Message objects separately from DOM nodes and jQuery objects
+                       if ( message instanceof mw.Message ) {
+                               $notificationContent.html( message.parse() );
+                       } else {
+                               $notificationContent.append( message );
+                       }
+               } else {
+                       $notificationContent.text( message );
+               }
+
+               $notificationContent.appendTo( $notification );
+
+               // Private state parameters, meant for internal use only
+               // autoHideSeconds: String alias for number of seconds for timeout of auto-hiding notifications.
+               // isOpen: Set to true after .start() is called to avoid double calls.
+               //         Set back to false after .close() to avoid duplicating the close animation.
+               // isPaused: false after .resume(), true after .pause(). Avoids duplicating or breaking the hide timeouts.
+               //           Set to true initially so .start() can call .resume().
+               // message: The message passed to the notification. Unused now but may be used in the future
+               //          to stop replacement of a tagged notification with another notification using the same message.
+               // options: The options passed to the notification with a little sanitization. Used by various methods.
+               // $notification: jQuery object containing the notification DOM node.
+               // timeout: Holds appropriate methods to set/clear timeouts
+               this.autoHideSeconds = options.autoHideSeconds &&
+                       notification.autoHideSeconds[ options.autoHideSeconds ] ||
+                       notification.autoHideSeconds.short;
+               this.isOpen = false;
+               this.isPaused = true;
+               this.message = message;
+               this.options = options;
+               this.$notification = $notification;
+               if ( options.visibleTimeout ) {
+                       this.timeout = require( 'mediawiki.visibleTimeout' );
+               } else {
+                       this.timeout = {
+                               set: setTimeout,
+                               clear: clearTimeout
+                       };
+               }
+       }
+
+       /**
+        * Start the notification. Called automatically by mw.notification#notify
+        * (possibly asynchronously on document-ready).
+        *
+        * This inserts the notification into the page, closes any matching tagged notifications,
+        * handles the fadeIn animations and replacement transitions, and starts autoHide timers.
+        *
+        * @private
+        */
+       Notification.prototype.start = function () {
+               var options, $notification, $tagMatches, autohideCount;
+
+               $area.css( 'display', '' );
+
+               if ( this.isOpen ) {
+                       return;
+               }
+
+               this.isOpen = true;
+               openNotificationCount++;
+
+               options = this.options;
+               $notification = this.$notification;
+
+               if ( options.tag ) {
+                       // Find notifications with the same tag
+                       $tagMatches = $area.find( '.mw-notification-tag-' + options.tag );
+               }
+
+               // If we found existing notification with the same tag, replace them
+               if ( options.tag && $tagMatches.length ) {
+
+                       // While there can be only one "open" notif with a given tag, there can be several
+                       // matches here because they remain in the DOM until the animation is finished.
+                       $tagMatches.each( function () {
+                               var notif = $( this ).data( 'mw.notification' );
+                               if ( notif && notif.isOpen ) {
+                                       // Detach from render flow with position absolute so that the new tag can
+                                       // occupy its space instead.
+                                       notif.$notification
+                                               .css( {
+                                                       position: 'absolute',
+                                                       width: notif.$notification.width()
+                                               } )
+                                               .css( notif.$notification.position() )
+                                               .addClass( 'mw-notification-replaced' );
+                                       notif.close();
+                               }
+                       } );
+
+                       $notification
+                               .insertBefore( $tagMatches.first() )
+                               .addClass( 'mw-notification-visible' );
+               } else {
+                       $area.append( $notification );
+                       rAF( function () {
+                               // This frame renders the element in the area (invisible)
+                               rAF( function () {
+                                       $notification.addClass( 'mw-notification-visible' );
+                               } );
+                       } );
+               }
+
+               // By default a notification is paused.
+               // If this notification is within the first {autoHideLimit} notifications then
+               // start the auto-hide timer as soon as it's created.
+               autohideCount = $area.find( '.mw-notification-autohide' ).length;
+               if ( autohideCount <= notification.autoHideLimit ) {
+                       this.resume();
+               }
+       };
+
+       /**
+        * Pause any running auto-hide timer for this notification
+        */
+       Notification.prototype.pause = function () {
+               if ( this.isPaused ) {
+                       return;
+               }
+               this.isPaused = true;
+
+               if ( this.timeoutId ) {
+                       this.timeout.clear( this.timeoutId );
+                       delete this.timeoutId;
+               }
+       };
+
+       /**
+        * Start autoHide timer if not already started.
+        * Does nothing if autoHide is disabled.
+        * Either to resume from pause or to make the first start.
+        */
+       Notification.prototype.resume = function () {
+               var notif = this;
+
+               if ( !notif.isPaused ) {
+                       return;
+               }
+               // Start any autoHide timeouts
+               if ( notif.options.autoHide ) {
+                       notif.isPaused = false;
+                       notif.timeoutId = notif.timeout.set( function () {
+                               // Already finished, so don't try to re-clear it
+                               delete notif.timeoutId;
+                               notif.close();
+                       }, this.autoHideSeconds * 1000 );
+               }
+       };
+
+       /**
+        * Close the notification.
+        */
+       Notification.prototype.close = function () {
+               var notif = this;
+
+               if ( !this.isOpen ) {
+                       return;
+               }
+
+               this.isOpen = false;
+               openNotificationCount--;
+
+               // Clear any remaining timeout on close
+               this.pause();
+
+               // Remove the mw-notification-autohide class from the notification to avoid
+               // having a half-closed notification counted as a notification to resume
+               // when handling {autoHideLimit}.
+               this.$notification.removeClass( 'mw-notification-autohide' );
+
+               // Now that a notification is being closed. Start auto-hide timers for any
+               // notification that has now become one of the first {autoHideLimit} notifications.
+               notification.resume();
+
+               rAF( function () {
+                       notif.$notification.removeClass( 'mw-notification-visible' );
+
+                       setTimeout( function () {
+                               if ( openNotificationCount === 0 ) {
+                                       // Hide the area after the last notification closes. Otherwise, the padding on
+                                       // the area can be obscure content, despite the area being empty/invisible (T54659). // FIXME
+                                       $area.css( 'display', 'none' );
+                                       notif.$notification.remove();
+                               } else {
+                                       notif.$notification.slideUp( 'fast', function () {
+                                               $( this ).remove();
+                                       } );
+                               }
+                       }, 500 );
+               } );
+       };
+
+       /**
+        * Helper function, take a list of notification divs and call
+        * a function on the Notification instance attached to them.
+        *
+        * @private
+        * @static
+        * @param {jQuery} $notifications A jQuery object containing notification divs
+        * @param {string} fn The name of the function to call on the Notification instance
+        */
+       function callEachNotification( $notifications, fn ) {
+               $notifications.each( function () {
+                       var notif = $( this ).data( 'mw.notification' );
+                       if ( notif ) {
+                               notif[ fn ]();
+                       }
+               } );
+       }
+
+       /**
+        * Initialisation.
+        * Must only be called once, and not before the document is ready.
+        *
+        * @ignore
+        */
+       function init() {
+               var offset, notif,
+                       isFloating = false;
+
+               function updateAreaMode() {
+                       var shouldFloat = window.pageYOffset > offset.top;
+                       if ( isFloating === shouldFloat ) {
+                               return;
+                       }
+                       isFloating = shouldFloat;
+                       $area
+                               .toggleClass( 'mw-notification-area-floating', isFloating )
+                               .toggleClass( 'mw-notification-area-layout', !isFloating );
+               }
+
+               // Write to the DOM:
+               // Prepend the notification area to the content area and save its object.
+               $area = $( '<div id="mw-notification-area" class="mw-notification-area mw-notification-area-layout"></div>' )
+                       // Pause auto-hide timers when the mouse is in the notification area.
+                       .on( {
+                               mouseenter: notification.pause,
+                               mouseleave: notification.resume
+                       } )
+                       // When clicking on a notification close it.
+                       .on( 'click', '.mw-notification', function () {
+                               var notif = $( this ).data( 'mw.notification' );
+                               if ( notif ) {
+                                       notif.close();
+                               }
+                       } )
+                       // Stop click events from <a> tags from propogating to prevent clicking.
+                       // on links from hiding a notification.
+                       .on( 'click', 'a', function ( e ) {
+                               e.stopPropagation();
+                       } );
+
+               mw.util.$content.prepend( $area );
+
+               // Read from the DOM:
+               // Must be in the next frame to avoid synchronous layout
+               // computation from offset()/getBoundingClientRect().
+               rAF( function () {
+                       offset = $area.offset();
+
+                       // Initial mode (reads, and then maybe writes)
+                       updateAreaMode();
+
+                       // Once we have the offset for where it would normally render, set the
+                       // initial state of the (currently empty) notification area to be hidden.
+                       $area.css( 'display', 'none' );
+
+                       $( window ).on( 'scroll', updateAreaMode );
+
+                       // Handle pre-ready queue.
+                       isPageReady = true;
+                       while ( preReadyNotifQueue.length ) {
+                               notif = preReadyNotifQueue.shift();
+                               notif.start();
+                       }
+               } );
+       }
+
+       /**
+        * @class mw.notification
+        * @singleton
+        */
+       notification = {
+               /**
+                * Pause auto-hide timers for all notifications.
+                * Notifications will not auto-hide until resume is called.
+                *
+                * @see mw.Notification#pause
+                */
+               pause: function () {
+                       callEachNotification(
+                               $area.children( '.mw-notification' ),
+                               'pause'
+                       );
+               },
+
+               /**
+                * Resume any paused auto-hide timers from the beginning.
+                * Only the first #autoHideLimit timers will be resumed.
+                */
+               resume: function () {
+                       callEachNotification(
+                               // Only call resume on the first #autoHideLimit notifications.
+                               // Exclude noautohide notifications to avoid bugs where #autoHideLimit
+                               // `{ autoHide: false }` notifications are at the start preventing any
+                               // auto-hide notifications from being autohidden.
+                               $area.children( '.mw-notification-autohide' ).slice( 0, notification.autoHideLimit ),
+                               'resume'
+                       );
+               },
+
+               /**
+                * Display a notification message to the user.
+                *
+                * @param {HTMLElement|HTMLElement[]|jQuery|mw.Message|string} message
+                * @param {Object} options The options to use for the notification.
+                *  See #defaults for details.
+                * @return {mw.Notification} Notification object
+                */
+               notify: function ( message, options ) {
+                       var notif;
+                       options = $.extend( {}, notification.defaults, options );
+
+                       notif = new Notification( message, options );
+
+                       if ( isPageReady ) {
+                               notif.start();
+                       } else {
+                               preReadyNotifQueue.push( notif );
+                       }
+
+                       return notif;
+               },
+
+               /**
+                * @property {Object}
+                * The defaults for #notify options parameter.
+                *
+                * - autoHide:
+                *   A boolean indicating whether the notifification should automatically
+                *   be hidden after shown. Or if it should persist.
+                *
+                * - autoHideSeconds:
+                *   Key to #autoHideSeconds for number of seconds for timeout of auto-hide
+                *   notifications.
+                *
+                * - tag:
+                *   An optional string. When a notification is tagged only one message
+                *   with that tag will be displayed. Trying to display a new notification
+                *   with the same tag as one already being displayed will cause the other
+                *   notification to be closed and this new notification to open up inside
+                *   the same place as the previous notification.
+                *
+                * - title:
+                *   An optional title for the notification. Will be displayed above the
+                *   content. Usually in bold.
+                *
+                * - type:
+                *   An optional string for the type of the message used for styling:
+                *   Examples: 'info', 'warn', 'error'.
+                *
+                * - visibleTimeout:
+                *   A boolean indicating if the autoHide timeout should be based on
+                *   time the page was visible to user. Or if it should use wall clock time.
+                */
+               defaults: {
+                       autoHide: true,
+                       autoHideSeconds: 'short',
+                       tag: null,
+                       title: null,
+                       type: null,
+                       visibleTimeout: true
+               },
+
+               /**
+                * @private
+                * @property {Object}
+                */
+               autoHideSeconds: {
+                       'short': 5,
+                       'long': 30
+               },
+
+               /**
+                * @property {number}
+                * Maximum number of simultaneous notifications to start auto-hide timers for.
+                * Only this number of notifications being displayed will be auto-hidden at one time.
+                * Any additional notifications in the list will only start counting their timeout for
+                * auto-hiding after the previous messages have been closed.
+                *
+                * This basically represents the minimal number of notifications the user should
+                * be able to process during the {@link #defaults default} #autoHideSeconds time.
+                */
+               autoHideLimit: 3
+       };
+
+       $( init );
+
+       mw.notification = notification;
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.notification/print.css b/resources/src/mediawiki.notification/print.css
new file mode 100644 (file)
index 0000000..4f9162e
--- /dev/null
@@ -0,0 +1,3 @@
+.mw-notification-area {
+       display: none;
+}
diff --git a/resources/src/mediawiki/mediawiki.notification.common.css b/resources/src/mediawiki/mediawiki.notification.common.css
deleted file mode 100644 (file)
index a1309c2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-.mw-notification-area {
-       position: absolute;
-}
-
-.mw-notification-area-floating {
-       position: fixed;
-}
diff --git a/resources/src/mediawiki/mediawiki.notification.css b/resources/src/mediawiki/mediawiki.notification.css
deleted file mode 100644 (file)
index a56be76..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-.mw-notification-area {
-       top: 0;
-       right: 0;
-       /* Padding on all sides so drop shadows aren't cut by overflow: hidden */
-       padding: 1em;
-       width: 20em;
-       line-height: 1.35;
-       z-index: 10000;
-       /* Avoid horizontal scrollbar on fade in and on fade out */
-       overflow: hidden;
-}
-
-.mw-notification {
-       padding: 0.75em 1.5em;
-       margin-bottom: 0.5em;
-       border: solid 1px #ddd;
-       background-color: #fff;
-       /* Click handler in mediawiki.notification.js */
-       cursor: pointer;
-
-       opacity: 0;
-       -webkit-transform: translateX( 35px );
-       transform: translateX( 35px );
-       -webkit-transition: opacity 0.35s ease-in-out, -webkit-transform 0.35s ease-in-out;
-       transition: opacity 0.35s ease-in-out, transform 0.35s ease-in-out;
-}
-
-.mw-notification-visible {
-       opacity: 1;
-       -webkit-transform: translateX( 0 );
-       transform: translateX( 0 );
-}
-
-.mw-notification-replaced {
-       opacity: 0;
-       -webkit-transform: translateY( -35px );
-       transform: translateY( -35px );
-       pointer-events: none;
-}
-
-.mw-notification-title {
-       font-weight: bold;
-}
-
-.mw-notification.mw-notification-type-warn {
-       border-color: #f5be00; /* yellow */
-       background-color: #ffffe8;
-}
-
-.mw-notification.mw-notification-type-error {
-       border-color: #eb3941; /* red */
-       background-color: #fff8f8;
-}
diff --git a/resources/src/mediawiki/mediawiki.notification.js b/resources/src/mediawiki/mediawiki.notification.js
deleted file mode 100644 (file)
index aa86a4b..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-( function ( mw, $ ) {
-       'use strict';
-
-       var notification,
-               // The #mw-notification-area div that all notifications are contained inside.
-               $area,
-               // Number of open notification boxes at any time
-               openNotificationCount = 0,
-               isPageReady = false,
-               preReadyNotifQueue = [],
-               rAF = window.requestAnimationFrame || setTimeout;
-
-       /**
-        * A Notification object for 1 message.
-        *
-        * The underscore in the name is to avoid a bug <https://github.com/senchalabs/jsduck/issues/304>.
-        * It is not part of the actual class name.
-        *
-        * The constructor is not publicly accessible; use mw.notification#notify instead.
-        * This does not insert anything into the document (see #start).
-        *
-        * @class mw.Notification_
-        * @alternateClassName mw.Notification
-        * @constructor
-        * @private
-        * @param {mw.Message|jQuery|HTMLElement|string} message
-        * @param {Object} options
-        */
-       function Notification( message, options ) {
-               var $notification, $notificationContent;
-
-               $notification = $( '<div class="mw-notification"></div>' )
-                       .data( 'mw.notification', this )
-                       .addClass( options.autoHide ? 'mw-notification-autohide' : 'mw-notification-noautohide' );
-
-               if ( options.tag ) {
-                       // Sanitize options.tag before it is used by any code. (Including Notification class methods)
-                       options.tag = options.tag.replace( /[ _-]+/g, '-' ).replace( /[^-a-z0-9]+/ig, '' );
-                       if ( options.tag ) {
-                               $notification.addClass( 'mw-notification-tag-' + options.tag );
-                       } else {
-                               delete options.tag;
-                       }
-               }
-
-               if ( options.type ) {
-                       // Sanitize options.type
-                       options.type = options.type.replace( /[ _-]+/g, '-' ).replace( /[^-a-z0-9]+/ig, '' );
-                       $notification.addClass( 'mw-notification-type-' + options.type );
-               }
-
-               if ( options.title ) {
-                       $( '<div class="mw-notification-title"></div>' )
-                               .text( options.title )
-                               .appendTo( $notification );
-               }
-
-               $notificationContent = $( '<div class="mw-notification-content"></div>' );
-
-               if ( typeof message === 'object' ) {
-                       // Handle mw.Message objects separately from DOM nodes and jQuery objects
-                       if ( message instanceof mw.Message ) {
-                               $notificationContent.html( message.parse() );
-                       } else {
-                               $notificationContent.append( message );
-                       }
-               } else {
-                       $notificationContent.text( message );
-               }
-
-               $notificationContent.appendTo( $notification );
-
-               // Private state parameters, meant for internal use only
-               // autoHideSeconds: String alias for number of seconds for timeout of auto-hiding notifications.
-               // isOpen: Set to true after .start() is called to avoid double calls.
-               //         Set back to false after .close() to avoid duplicating the close animation.
-               // isPaused: false after .resume(), true after .pause(). Avoids duplicating or breaking the hide timeouts.
-               //           Set to true initially so .start() can call .resume().
-               // message: The message passed to the notification. Unused now but may be used in the future
-               //          to stop replacement of a tagged notification with another notification using the same message.
-               // options: The options passed to the notification with a little sanitization. Used by various methods.
-               // $notification: jQuery object containing the notification DOM node.
-               // timeout: Holds appropriate methods to set/clear timeouts
-               this.autoHideSeconds = options.autoHideSeconds &&
-                       notification.autoHideSeconds[ options.autoHideSeconds ] ||
-                       notification.autoHideSeconds.short;
-               this.isOpen = false;
-               this.isPaused = true;
-               this.message = message;
-               this.options = options;
-               this.$notification = $notification;
-               if ( options.visibleTimeout ) {
-                       this.timeout = require( 'mediawiki.visibleTimeout' );
-               } else {
-                       this.timeout = {
-                               set: setTimeout,
-                               clear: clearTimeout
-                       };
-               }
-       }
-
-       /**
-        * Start the notification. Called automatically by mw.notification#notify
-        * (possibly asynchronously on document-ready).
-        *
-        * This inserts the notification into the page, closes any matching tagged notifications,
-        * handles the fadeIn animations and replacement transitions, and starts autoHide timers.
-        *
-        * @private
-        */
-       Notification.prototype.start = function () {
-               var options, $notification, $tagMatches, autohideCount;
-
-               $area.css( 'display', '' );
-
-               if ( this.isOpen ) {
-                       return;
-               }
-
-               this.isOpen = true;
-               openNotificationCount++;
-
-               options = this.options;
-               $notification = this.$notification;
-
-               if ( options.tag ) {
-                       // Find notifications with the same tag
-                       $tagMatches = $area.find( '.mw-notification-tag-' + options.tag );
-               }
-
-               // If we found existing notification with the same tag, replace them
-               if ( options.tag && $tagMatches.length ) {
-
-                       // While there can be only one "open" notif with a given tag, there can be several
-                       // matches here because they remain in the DOM until the animation is finished.
-                       $tagMatches.each( function () {
-                               var notif = $( this ).data( 'mw.notification' );
-                               if ( notif && notif.isOpen ) {
-                                       // Detach from render flow with position absolute so that the new tag can
-                                       // occupy its space instead.
-                                       notif.$notification
-                                               .css( {
-                                                       position: 'absolute',
-                                                       width: notif.$notification.width()
-                                               } )
-                                               .css( notif.$notification.position() )
-                                               .addClass( 'mw-notification-replaced' );
-                                       notif.close();
-                               }
-                       } );
-
-                       $notification
-                               .insertBefore( $tagMatches.first() )
-                               .addClass( 'mw-notification-visible' );
-               } else {
-                       $area.append( $notification );
-                       rAF( function () {
-                               // This frame renders the element in the area (invisible)
-                               rAF( function () {
-                                       $notification.addClass( 'mw-notification-visible' );
-                               } );
-                       } );
-               }
-
-               // By default a notification is paused.
-               // If this notification is within the first {autoHideLimit} notifications then
-               // start the auto-hide timer as soon as it's created.
-               autohideCount = $area.find( '.mw-notification-autohide' ).length;
-               if ( autohideCount <= notification.autoHideLimit ) {
-                       this.resume();
-               }
-       };
-
-       /**
-        * Pause any running auto-hide timer for this notification
-        */
-       Notification.prototype.pause = function () {
-               if ( this.isPaused ) {
-                       return;
-               }
-               this.isPaused = true;
-
-               if ( this.timeoutId ) {
-                       this.timeout.clear( this.timeoutId );
-                       delete this.timeoutId;
-               }
-       };
-
-       /**
-        * Start autoHide timer if not already started.
-        * Does nothing if autoHide is disabled.
-        * Either to resume from pause or to make the first start.
-        */
-       Notification.prototype.resume = function () {
-               var notif = this;
-
-               if ( !notif.isPaused ) {
-                       return;
-               }
-               // Start any autoHide timeouts
-               if ( notif.options.autoHide ) {
-                       notif.isPaused = false;
-                       notif.timeoutId = notif.timeout.set( function () {
-                               // Already finished, so don't try to re-clear it
-                               delete notif.timeoutId;
-                               notif.close();
-                       }, this.autoHideSeconds * 1000 );
-               }
-       };
-
-       /**
-        * Close the notification.
-        */
-       Notification.prototype.close = function () {
-               var notif = this;
-
-               if ( !this.isOpen ) {
-                       return;
-               }
-
-               this.isOpen = false;
-               openNotificationCount--;
-
-               // Clear any remaining timeout on close
-               this.pause();
-
-               // Remove the mw-notification-autohide class from the notification to avoid
-               // having a half-closed notification counted as a notification to resume
-               // when handling {autoHideLimit}.
-               this.$notification.removeClass( 'mw-notification-autohide' );
-
-               // Now that a notification is being closed. Start auto-hide timers for any
-               // notification that has now become one of the first {autoHideLimit} notifications.
-               notification.resume();
-
-               rAF( function () {
-                       notif.$notification.removeClass( 'mw-notification-visible' );
-
-                       setTimeout( function () {
-                               if ( openNotificationCount === 0 ) {
-                                       // Hide the area after the last notification closes. Otherwise, the padding on
-                                       // the area can be obscure content, despite the area being empty/invisible (T54659). // FIXME
-                                       $area.css( 'display', 'none' );
-                                       notif.$notification.remove();
-                               } else {
-                                       notif.$notification.slideUp( 'fast', function () {
-                                               $( this ).remove();
-                                       } );
-                               }
-                       }, 500 );
-               } );
-       };
-
-       /**
-        * Helper function, take a list of notification divs and call
-        * a function on the Notification instance attached to them.
-        *
-        * @private
-        * @static
-        * @param {jQuery} $notifications A jQuery object containing notification divs
-        * @param {string} fn The name of the function to call on the Notification instance
-        */
-       function callEachNotification( $notifications, fn ) {
-               $notifications.each( function () {
-                       var notif = $( this ).data( 'mw.notification' );
-                       if ( notif ) {
-                               notif[ fn ]();
-                       }
-               } );
-       }
-
-       /**
-        * Initialisation.
-        * Must only be called once, and not before the document is ready.
-        *
-        * @ignore
-        */
-       function init() {
-               var offset, notif,
-                       isFloating = false;
-
-               function updateAreaMode() {
-                       var shouldFloat = window.pageYOffset > offset.top;
-                       if ( isFloating === shouldFloat ) {
-                               return;
-                       }
-                       isFloating = shouldFloat;
-                       $area
-                               .toggleClass( 'mw-notification-area-floating', isFloating )
-                               .toggleClass( 'mw-notification-area-layout', !isFloating );
-               }
-
-               // Write to the DOM:
-               // Prepend the notification area to the content area and save its object.
-               $area = $( '<div id="mw-notification-area" class="mw-notification-area mw-notification-area-layout"></div>' )
-                       // Pause auto-hide timers when the mouse is in the notification area.
-                       .on( {
-                               mouseenter: notification.pause,
-                               mouseleave: notification.resume
-                       } )
-                       // When clicking on a notification close it.
-                       .on( 'click', '.mw-notification', function () {
-                               var notif = $( this ).data( 'mw.notification' );
-                               if ( notif ) {
-                                       notif.close();
-                               }
-                       } )
-                       // Stop click events from <a> tags from propogating to prevent clicking.
-                       // on links from hiding a notification.
-                       .on( 'click', 'a', function ( e ) {
-                               e.stopPropagation();
-                       } );
-
-               mw.util.$content.prepend( $area );
-
-               // Read from the DOM:
-               // Must be in the next frame to avoid synchronous layout
-               // computation from offset()/getBoundingClientRect().
-               rAF( function () {
-                       offset = $area.offset();
-
-                       // Initial mode (reads, and then maybe writes)
-                       updateAreaMode();
-
-                       // Once we have the offset for where it would normally render, set the
-                       // initial state of the (currently empty) notification area to be hidden.
-                       $area.css( 'display', 'none' );
-
-                       $( window ).on( 'scroll', updateAreaMode );
-
-                       // Handle pre-ready queue.
-                       isPageReady = true;
-                       while ( preReadyNotifQueue.length ) {
-                               notif = preReadyNotifQueue.shift();
-                               notif.start();
-                       }
-               } );
-       }
-
-       /**
-        * @class mw.notification
-        * @singleton
-        */
-       notification = {
-               /**
-                * Pause auto-hide timers for all notifications.
-                * Notifications will not auto-hide until resume is called.
-                *
-                * @see mw.Notification#pause
-                */
-               pause: function () {
-                       callEachNotification(
-                               $area.children( '.mw-notification' ),
-                               'pause'
-                       );
-               },
-
-               /**
-                * Resume any paused auto-hide timers from the beginning.
-                * Only the first #autoHideLimit timers will be resumed.
-                */
-               resume: function () {
-                       callEachNotification(
-                               // Only call resume on the first #autoHideLimit notifications.
-                               // Exclude noautohide notifications to avoid bugs where #autoHideLimit
-                               // `{ autoHide: false }` notifications are at the start preventing any
-                               // auto-hide notifications from being autohidden.
-                               $area.children( '.mw-notification-autohide' ).slice( 0, notification.autoHideLimit ),
-                               'resume'
-                       );
-               },
-
-               /**
-                * Display a notification message to the user.
-                *
-                * @param {HTMLElement|HTMLElement[]|jQuery|mw.Message|string} message
-                * @param {Object} options The options to use for the notification.
-                *  See #defaults for details.
-                * @return {mw.Notification} Notification object
-                */
-               notify: function ( message, options ) {
-                       var notif;
-                       options = $.extend( {}, notification.defaults, options );
-
-                       notif = new Notification( message, options );
-
-                       if ( isPageReady ) {
-                               notif.start();
-                       } else {
-                               preReadyNotifQueue.push( notif );
-                       }
-
-                       return notif;
-               },
-
-               /**
-                * @property {Object}
-                * The defaults for #notify options parameter.
-                *
-                * - autoHide:
-                *   A boolean indicating whether the notifification should automatically
-                *   be hidden after shown. Or if it should persist.
-                *
-                * - autoHideSeconds:
-                *   Key to #autoHideSeconds for number of seconds for timeout of auto-hide
-                *   notifications.
-                *
-                * - tag:
-                *   An optional string. When a notification is tagged only one message
-                *   with that tag will be displayed. Trying to display a new notification
-                *   with the same tag as one already being displayed will cause the other
-                *   notification to be closed and this new notification to open up inside
-                *   the same place as the previous notification.
-                *
-                * - title:
-                *   An optional title for the notification. Will be displayed above the
-                *   content. Usually in bold.
-                *
-                * - type:
-                *   An optional string for the type of the message used for styling:
-                *   Examples: 'info', 'warn', 'error'.
-                *
-                * - visibleTimeout:
-                *   A boolean indicating if the autoHide timeout should be based on
-                *   time the page was visible to user. Or if it should use wall clock time.
-                */
-               defaults: {
-                       autoHide: true,
-                       autoHideSeconds: 'short',
-                       tag: null,
-                       title: null,
-                       type: null,
-                       visibleTimeout: true
-               },
-
-               /**
-                * @private
-                * @property {Object}
-                */
-               autoHideSeconds: {
-                       'short': 5,
-                       'long': 30
-               },
-
-               /**
-                * @property {number}
-                * Maximum number of simultaneous notifications to start auto-hide timers for.
-                * Only this number of notifications being displayed will be auto-hidden at one time.
-                * Any additional notifications in the list will only start counting their timeout for
-                * auto-hiding after the previous messages have been closed.
-                *
-                * This basically represents the minimal number of notifications the user should
-                * be able to process during the {@link #defaults default} #autoHideSeconds time.
-                */
-               autoHideLimit: 3
-       };
-
-       $( init );
-
-       mw.notification = notification;
-
-}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.notification.print.css b/resources/src/mediawiki/mediawiki.notification.print.css
deleted file mode 100644 (file)
index 4f9162e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-.mw-notification-area {
-       display: none;
-}