summaryrefslogtreecommitdiff
path: root/resources/mediawiki/mediawiki.notification.js
diff options
context:
space:
mode:
Diffstat (limited to 'resources/mediawiki/mediawiki.notification.js')
-rw-r--r--resources/mediawiki/mediawiki.notification.js504
1 files changed, 0 insertions, 504 deletions
diff --git a/resources/mediawiki/mediawiki.notification.js b/resources/mediawiki/mediawiki.notification.js
deleted file mode 100644
index 4ede8096..00000000
--- a/resources/mediawiki/mediawiki.notification.js
+++ /dev/null
@@ -1,504 +0,0 @@
-( function ( mw, $ ) {
- 'use strict';
-
- var notification,
- // The #mw-notification-area div that all notifications are contained inside.
- $area,
- isPageReady = false,
- preReadyNotifQueue = [];
-
- /**
- * Creates a Notification object for 1 message.
- * Does not insert anything into the document (see #start).
- *
- * The "_" in the name is to avoid a bug (http://github.com/senchalabs/jsduck/issues/304)
- * It is not part of the actual class name.
- *
- * @class mw.Notification_
- * @alternateClassName mw.Notification
- * @private
- *
- * @constructor
- */
- function Notification( message, options ) {
- var $notification, $notificationTitle, $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.title ) {
- $notificationTitle = $( '<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
- // 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.
- this.isOpen = false;
- this.isPaused = true;
- this.message = message;
- this.options = options;
- this.$notification = $notification;
- }
-
- /**
- * Start the notification.
- * This inserts it into the page, closes any matching tagged notifications,
- * handles the fadeIn animations and repacement transitions, and starts autoHide timers.
- */
- Notification.prototype.start = function () {
- var
- // Local references
- $notification, options,
- // Original opacity so that we can animate back to it later
- opacity,
- // Other notification elements matching the same tag
- $tagMatches,
- outerHeight,
- placeholderHeight,
- autohideCount,
- notif;
-
- if ( this.isOpen ) {
- return;
- }
-
- this.isOpen = true;
-
- options = this.options;
- $notification = this.$notification;
-
- opacity = this.$notification.css( 'opacity' );
-
- // Set the opacity to 0 so we can fade in later.
- $notification.css( 'opacity', 0 );
-
- if ( options.tag ) {
- // Check to see if there are any tagged notifications with the same tag as the new one
- $tagMatches = $area.find( '.mw-notification-tag-' + options.tag );
- }
-
- // If we found a tagged notification use the replacement pattern instead of the new
- // notification fade-in pattern.
- if ( options.tag && $tagMatches.length ) {
-
- // Iterate over the tag matches to find the outerHeight we should use
- // for the placeholder.
- outerHeight = 0;
- $tagMatches.each( function () {
- var notif = $( this ).data( 'mw.notification' );
- if ( notif ) {
- // Use the notification's height + padding + border + margins
- // as the placeholder height.
- outerHeight = notif.$notification.outerHeight( true );
- if ( notif.$replacementPlaceholder ) {
- // Grab the height of a placeholder that has not finished animating.
- placeholderHeight = notif.$replacementPlaceholder.height();
- // Remove any placeholders added by a previous tagged
- // notification that was in the middle of replacing another.
- // This also makes sure that we only grab the placeholderHeight
- // for the most recent notification.
- notif.$replacementPlaceholder.remove();
- delete notif.$replacementPlaceholder;
- }
- // Close the previous tagged notification
- // Since we're replacing it do this with a fast speed and don't output a placeholder
- // since we're taking care of that transition ourselves.
- notif.close( { speed: 'fast', placeholder: false } );
- }
- } );
- if ( placeholderHeight !== undefined ) {
- // If the other tagged notification was in the middle of replacing another
- // tagged notification, continue from the placeholder's height instead of
- // using the outerHeight of the notification.
- outerHeight = placeholderHeight;
- }
-
- $notification
- // Insert the new notification before the tagged notification(s)
- .insertBefore( $tagMatches.first() )
- .css( {
- // Use an absolute position so that we can use a placeholder to gracefully push other notifications
- // into the right spot.
- position: 'absolute',
- width: $notification.width()
- } )
- // Fade-in the notification
- .animate( { opacity: opacity },
- {
- duration: 'slow',
- complete: function () {
- // After we've faded in clear the opacity and let css take over
- $( this ).css( { opacity: '' } );
- }
- } );
-
- notif = this;
-
- // Create a clear placeholder we can use to make the notifications around the notification that is being
- // replaced expand or contract gracefully to fit the height of the new notification.
- notif.$replacementPlaceholder = $( '<div>' )
- // Set the height to the space the previous notification or placeholder took
- .css( 'height', outerHeight )
- // Make sure that this placeholder is at the very end of this tagged notification group
- .insertAfter( $tagMatches.eq( -1 ) )
- // Animate the placeholder height to the space that this new notification will take up
- .animate( { height: $notification.outerHeight( true ) },
- {
- // Do space animations fast
- speed: 'fast',
- complete: function () {
- // Reset the notification position after we've finished the space animation
- // However do not do it if the placeholder was removed because another tagged
- // notification went and closed this one.
- if ( notif.$replacementPlaceholder ) {
- $notification.css( 'position', '' );
- }
- // Finally, remove the placeholder from the DOM
- $( this ).remove();
- }
- } );
- } else {
- // Append to the notification area and fade in to the original opacity.
- $notification
- .appendTo( $area )
- .animate( { opacity: opacity },
- {
- duration: 'fast',
- complete: function () {
- // After we've faded in clear the opacity and let css take over
- $( this ).css( 'opacity', '' );
- }
- }
- );
- }
-
- // 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.timeout ) {
- clearTimeout( this.timeout );
- delete this.timeout;
- }
- };
-
- /**
- * 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.timeout = setTimeout( function () {
- // Already finished, so don't try to re-clear it
- delete notif.timeout;
- notif.close();
- }, notification.autoHideSeconds * 1000 );
- }
- };
-
- /**
- * Close/hide the notification.
- *
- * @param {Object} options An object containing options for the closing of the notification.
- * These are typically only used internally.
- *
- * - speed: Use a close speed different than the default 'slow'.
- * - placeholder: Set to false to disable the placeholder transition.
- */
- Notification.prototype.close = function ( options ) {
- if ( !this.isOpen ) {
- return;
- }
- this.isOpen = false;
- // Clear any remaining timeout on close
- this.pause();
-
- options = $.extend( {
- speed: 'slow',
- placeholder: true
- }, options );
-
- // 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();
-
- this.$notification
- .css( {
- // Don't trigger any mouse events while fading out, just in case the cursor
- // happens to be right above us when we transition upwards.
- pointerEvents: 'none',
- // Set an absolute position so we can move upwards in the animation.
- // Notification replacement doesn't look right unless we use an animation like this.
- position: 'absolute',
- // We must fix the width to avoid it shrinking horizontally.
- width: this.$notification.width()
- } )
- // Fix the top/left position to the current computed position from which we
- // can animate upwards.
- .css( this.$notification.position() );
-
- // This needs to be done *after* notification's position has been made absolute.
- if ( options.placeholder ) {
- // Insert a placeholder with a height equal to the height of the
- // notification plus it's vertical margins in place of the notification
- var $placeholder = $( '<div>' )
- .css( 'height', this.$notification.outerHeight( true ) )
- .insertBefore( this.$notification );
- }
-
- // Animate opacity and top to create fade upwards animation for notification closing
- this.$notification
- .animate( {
- opacity: 0,
- top: '-=35'
- }, {
- duration: options.speed,
- complete: function () {
- // Remove the notification
- $( this ).remove();
- if ( options.placeholder ) {
- // Use a fast slide up animation after closing to make it look like the notifications
- // below slide up into place when the notification disappears
- $placeholder.slideUp( 'fast', function () {
- // Remove the placeholder
- $( this ).remove();
- } );
- }
- }
- } );
- };
-
- /**
- * Helper function, take a list of notification divs and call
- * a function on the Notification instance attached to them.
- *
- * @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, $window = $( window );
-
- $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();
- } );
-
- // Prepend the notification area to the content area and save it's object.
- mw.util.$content.prepend( $area );
- offset = $area.offset();
-
- function updateAreaMode() {
- var isFloating = $window.scrollTop() > offset.top;
- $area
- .toggleClass( 'mw-notification-area-floating', isFloating )
- .toggleClass( 'mw-notification-area-layout', !isFloating );
- }
-
- $window.on( 'scroll', updateAreaMode );
-
- // Initial mode
- updateAreaMode();
- }
-
- /**
- * @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|jQuery|mw.Message|string} message
- * @param {Object} options The options to use for the notification.
- * See #defaults for details.
- * @return {Object} Object with a close function to close the notification
- */
- 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 { close: $.proxy( notif.close, 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.
- *
- * - 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.
- */
- defaults: {
- autoHide: true,
- tag: false,
- title: undefined
- },
-
- /**
- * @property {number}
- * Number of seconds to wait before auto-hiding notifications.
- */
- autoHideSeconds: 5,
-
- /**
- * @property {number}
- * Maximum number of notifications to count down auto-hide timers for.
- * Only the first #autoHideLimit notifications being displayed will
- * auto-hide. Any notifications further down in the list will only start
- * counting down to auto-hide after the first few messages have closed.
- *
- * This basically represents the number of notifications the user should
- * be able to process in #autoHideSeconds time.
- */
- autoHideLimit: 3
- };
-
- $( function () {
- var notif;
-
- init();
-
- // Handle pre-ready queue.
- isPageReady = true;
- while ( preReadyNotifQueue.length ) {
- notif = preReadyNotifQueue.shift();
- notif.start();
- }
- } );
-
- mw.notification = notification;
-
-}( mediaWiki, jQuery ) );