jenkins-bot has submitted this change and it was merged.

Change subject: mediawiki.notification: Use CSS tranforms for in/out animations
......................................................................


mediawiki.notification: Use CSS tranforms for in/out animations

Remove the whole placeholder system. This was needed to preserve
parking space while visually animating the element elsewhere.
CSS transforms have this behaviour naturally.

Change-Id: I01473a199665b9fd86ed50b7d117532ac94f3edf
---
M resources/src/mediawiki/mediawiki.notification.css
M resources/src/mediawiki/mediawiki.notification.js
2 files changed, 66 insertions(+), 163 deletions(-)

Approvals:
  Ori.livneh: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/resources/src/mediawiki/mediawiki.notification.css 
b/resources/src/mediawiki/mediawiki.notification.css
index 632ae82..82ccd4f 100644
--- a/resources/src/mediawiki/mediawiki.notification.css
+++ b/resources/src/mediawiki/mediawiki.notification.css
@@ -12,9 +12,27 @@
        margin-bottom: 0.5em;
        border: solid 1px #ddd;
        background-color: #fcfcfc;
-       /* Message hides on-click */
-       /* See also mediawiki.notification.js */
+       /* 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 {
diff --git a/resources/src/mediawiki/mediawiki.notification.js 
b/resources/src/mediawiki/mediawiki.notification.js
index eeb7bb3..3f7b8fd 100644
--- a/resources/src/mediawiki/mediawiki.notification.js
+++ b/resources/src/mediawiki/mediawiki.notification.js
@@ -7,7 +7,8 @@
                // Number of open notification boxes at any time
                openNotificationCount = 0,
                isPageReady = false,
-               preReadyNotifQueue = [];
+               preReadyNotifQueue = [],
+               rAF = window.requestAnimationFrame || setTimeout;
 
        /**
         * A Notification object for 1 message.
@@ -92,17 +93,7 @@
         * @private
         */
        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;
+               var options, $notification, $tagMatches, autohideCount;
 
                $area.show();
 
@@ -116,109 +107,43 @@
                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
+                       // Find notifications with the same tag
                        $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 we found existing notification with the same tag, replace 
them
                if ( options.tag && $tagMatches.length ) {
 
-                       // Iterate over the tag matches to find the outerHeight 
we should use
-                       // for the placeholder.
-                       outerHeight = 0;
+                       // 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 ) {
-                                       // 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 ( 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();
                                }
                        } );
-                       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();
-                                               }
-                                       } );
+                               .addClass( 'mw-notification-visible' );
                } 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', '' );
-                                               }
-                                       }
-                               );
+                       $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.
@@ -267,26 +192,20 @@
        };
 
        /**
-        * Close/hide the notification.
-        *
-        * @param {Object} options An object containing options for the closing 
of the notification.
-        *
-        *  - speed: Use a close speed different than the default 'slow'.
-        *  - placeholder: Set to false to disable the placeholder transition.
+        * Close the notification.
         */
-       Notification.prototype.close = function ( options ) {
+       Notification.prototype.close = function () {
+               var notif = this;
+
                if ( !this.isOpen ) {
                        return;
                }
+
                this.isOpen = false;
                openNotificationCount--;
+
                // 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
@@ -297,56 +216,22 @@
                // 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() );
+               rAF( function () {
+                       notif.$notification.removeClass( 
'mw-notification-visible' );
 
-               // 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();
-                                       // Hide the area manually after closing 
the last notification, since it has padding,
-                                       // causing it to obscure whatever is 
behind it in spite of being invisible (bug 52659).
-                                       // It's okay to do this before getting 
rid of the placeholder, as it's invisible as well.
-                                       if ( openNotificationCount === 0 ) {
-                                               $area.hide();
-                                       }
-                                       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();
-                                               } );
-                                       }
+                       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.hide();
+                                       notif.$notification.remove();
+                               } else {
+                                       notif.$notification.slideUp( 'fast',  
function () {
+                                               $( this ).remove();
+                                       } );
                                }
-                       } );
+                       }, 500 );
+               } );
        };
 
        /**

-- 
To view, visit https://gerrit.wikimedia.org/r/241262
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I01473a199665b9fd86ed50b7d117532ac94f3edf
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Krinkle <[email protected]>
Gerrit-Reviewer: Bartosz DziewoƄski <[email protected]>
Gerrit-Reviewer: Daniel Friesen <[email protected]>
Gerrit-Reviewer: Edokter <[email protected]>
Gerrit-Reviewer: Gilles <[email protected]>
Gerrit-Reviewer: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Ori.livneh <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to