Daniel Werner has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/79147


Change subject: toggler & inputextender: Replaced "animationstep" events with 
"animation" event
......................................................................

toggler & inputextender: Replaced "animationstep" events with "animation" event

This is done by using jQuery.fn.animateWithEvent. Should give a little 
performance boost during
animation executions since only one event will be triggered and bubble up the 
DOM per animation
(before, an "animationstep" event got fired for each animation step and on 
completion, though
using different parameters depending on the occasion).
- Allow for greater flexibility when using the event, extensions such as 
widgets can now hook into
  all animation stages.
- Resolved the ugliness of jQuery.ui.toggler specific handling in 
jQuery.ui.inputextender.
- Introduces another new event for inputextender, "contentanimation" which 
fires on the widget in
  case the new "contentAnimationEvents" option is specified with the name of an 
event triggered
  on the inputexter's extension node.

Change-Id: If57ee1eea13d1d016915b8e06b8e9cea05c63b5e
---
M ValueView/ValueView.resources.mw.php
M ValueView/resources/jquery.ui/jquery.ui.inputextender.js
M ValueView/resources/jquery.ui/jquery.ui.toggler.js
M 
ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
M ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
M ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
6 files changed, 83 insertions(+), 64 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues 
refs/changes/47/79147/1

diff --git a/ValueView/ValueView.resources.mw.php 
b/ValueView/ValueView.resources.mw.php
index f4bd0ab..0286208 100644
--- a/ValueView/ValueView.resources.mw.php
+++ b/ValueView/ValueView.resources.mw.php
@@ -135,6 +135,7 @@
                                'jquery.eachchange',
                                'jquery.ui.position',
                                'jquery.ui.widget',
+                               'jquery.animateWithEvent',
                        ),
                ),
 
@@ -147,6 +148,7 @@
                        ),
                        'dependencies' => array(
                                'jquery.ui.widget',
+                               'jquery.animateWithEvent',
                        ),
                ),
 
diff --git a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js 
b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
index 1df5bc2..e897667 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.inputextender.js
@@ -20,13 +20,19 @@
  *         hidden when the associated input element is empty.
  *         Default value: true
  *
- * @event animationstep: While the input extender's extension is being 
animated, this event is
- *        triggered on each animation step. The event forwards the parameters 
received from the
- *        animation's "step" callback. However, when the animation is 
finished, the event is
- *        triggered without the second and third parameter.
- *        (1) {jQuery.Event}
- *        (2) {number|undefined} [now]
- *        (3) {jQuery.Tween|undefined} [tween]
+ * @option {string} [contentAnimationEvents] One or more events (separated 
with spaces) which imply
+ *         that the input extenders extension's content is about to be 
animated. Those events should
+ *         give a jQuery.AnimationEvent object as their event object. If this 
is the case and the
+ *         event bubbles up to the input extender's extension node, then this 
will trigger the
+ *         "contentanimation" event on the widget node.
+ *
+ * @event animation: Triggered at the beginning of an animation of the input's 
extension.
+ *        (1) {jQuery.AnimationEvent} animationEvent
+ *
+ * @event contentanimation: Triggered at the beginning of an animation of the 
extender's
+ *        extension content. Depends on the "contentAnimationEvents" option.
+ *        (1) {jQuery.AnimationEvent} animationEvent The animation event gets 
passed on from the
+ *            event within the input extender's extension causing the 
"contentanimation" event.
  *
  * @dependency jQuery.Widget
  * @dependency jQuery.eachchange
@@ -77,6 +83,7 @@
                 */
                options: {
                        content: [],
+                       contentAnimationEvents: '',
                        initCallback: null,
                        hideWhenInputEmpty: true,
                        position: {
@@ -218,7 +225,7 @@
                /**
                 * Shows the extension.
                 *
-                * @param {Function} [callback] Invoked as soon as the contents 
are visible.
+                * @param {Function} [callback] Invoked as soon as the 
extension's show animation is done.
                 */
                showExtension: function( callback ) {
                        if( !this._isExtended ) {
@@ -230,7 +237,7 @@
                /**
                 * Hides the extension.
                 *
-                * @param {Function} [callback] Invoked as soon as the contents 
are hidden.
+                * @param {Function} [callback] Invoked as soon as the 
extension's hide animation is done.
                 */
                hideExtension: function( callback ) {
                        if( this._isExtended ) {
@@ -273,12 +280,6 @@
 
                /**
                 * Draws the widget.
-                *
-                * @param {Function} [callback] For private usage only.
-                * TODO: Get rid of "callback", introduce some sort of 
"animationstart" event instead,
-                *  offering an object allowing to register callback that will 
be given into the animation's
-                *  options. show/hideExtension can then do a .one() event 
registration for that one and
-                *  register their callback there.
                 */
                draw: function( /* private: */ callback ) {
                        this.element[ this._isExtended ? 'addClass' : 
'removeClass' ](
@@ -300,7 +301,6 @@
                                this.$extension = $extension = 
this._buildExtension();
                                $extension.appendTo( $( 'body' ) );
 
-                               // TODO
                                if( $.isFunction( this.options.initCallback ) ) 
{
                                        $extension.show();
                                        this.options.initCallback.call( this, 
$extension );
@@ -337,37 +337,43 @@
                                this.$extension.css( 'opacity', '1' );
                        }
 
-                       this.$extension.stop( true ).fadeIn( {
-                               duration: 150,
-                               step: function( now, tween ) {
-                                       self._trigger( 'animationstep', null, [ 
now, tween ] );
-                               },
-                               complete: function() {
-                                       if( $.isFunction( callback ) ) {
-                                               callback();
+                       this.$extension.stop( true ).animateWithEvent(
+                               'extensionexpansion',
+                               'fadeIn',
+                               {
+                                       duration: 150,
+                                       complete: function() {
+                                               if( $.isFunction( callback ) ) {
+                                                       callback();
+                                               }
                                        }
-                                       self._trigger( 'animationstep' );
+                               },
+                               function( animationEvent ) {
+                                       self._trigger( 'animation', 
animationEvent );
                                }
-                       } );
+                       );
                        inputExtendersWithVisibleExtension.add( this );
                },
 
                _drawExtensionRemoval: function( callback ) {
                        var self = this;
 
-                       this.$extension.stop( true ).fadeOut( {
-                               duration: 150,
-                               step: function( now, tween ) {
-                                       self._trigger( 'animationstep', null, [ 
now, tween ] );
-                               },
-                               complete: function() {
-                                       
inputExtendersWithVisibleExtension.remove( this );
-                                       if( $.isFunction( callback ) ) {
-                                               callback();
+                       this.$extension.stop( true ).animateWithEvent(
+                               'extensionremoval',
+                               'fadeOut',
+                               {
+                                       duration: 150,
+                                       complete: function() {
+                                               
inputExtendersWithVisibleExtension.remove( self );
+                                               if( $.isFunction( callback ) ) {
+                                                       callback();
+                                               }
                                        }
-                                       self._trigger( 'animationstep' );
+                               },
+                               function( animationEvent ) {
+                                       self._trigger( 'animation', 
animationEvent );
                                }
-                       } );
+                       );
                },
 
                /**
@@ -410,10 +416,8 @@
                                        self.showExtension();
                                }
                        } )
-                       // TODO: move this out of here, toggler is not even 
used/known to this widget:
-                       .on( 'toggleranimationstep.' + this.widgetName, 
function( event, now, tween ) {
-                               self._reposition();
-                               self._trigger( 'animationstep', null, [ now, 
tween ] );
+                       .on( this.options.contentAnimationEvents, function( 
animationEvent ) {
+                               self._trigger( 'contentanimation', 
animationEvent );
                        } )
                        .on( 'keydown.' + this.widgetName, function( event ) {
                                // Take care of tabbing out of the extension 
again:
diff --git a/ValueView/resources/jquery.ui/jquery.ui.toggler.js 
b/ValueView/resources/jquery.ui/jquery.ui.toggler.js
index a4b20f8..442a5e7 100644
--- a/ValueView/resources/jquery.ui/jquery.ui.toggler.js
+++ b/ValueView/resources/jquery.ui/jquery.ui.toggler.js
@@ -11,12 +11,8 @@
  *
  * @option {jQuery} $subject (REQUIRED) The node whose visibility shall be 
toggled.
  *
- * @event animationstep: While the toggler is being animated, this event is 
triggered on each
- *        animation step. The event forwards the parameters received from the 
animation's "step"
- *        callback.
- *        (1) {jQuery.Event}
- *        (2) {number} now
- *        (3) {jQuery.Tween} tween
+ * @event 'animation' Triggered at the beginning of toggler animations.
+ *        (1) {jQuery.AnimationEvent} event
  *
  * @dependency jQuery.Widget
  */
@@ -96,7 +92,8 @@
 
                        this.element
                        .text( '' )
-                       .addClass( this.widgetBaseClass +  ' ' + 
this.widgetBaseClass + '-toggle ' + 'ui-state-default' );
+                       .addClass( this.widgetBaseClass + ' ' + 
this.widgetBaseClass + '-toggle '
+                               + 'ui-state-default' );
 
                        if( this.element[0].nodeName === 'A' ) {
                                this.element.attr( 'href', 
'javascript:void(0);' );
@@ -110,11 +107,14 @@
                                if( !self.element.hasClass( 'ui-state-disabled' 
) ) {
                                        // Change toggle icon to reflect 
current state of toggle subject visibility:
                                        self._reflectVisibilityOnToggleIcon( 
true );
-                                       self.options.$subject.slideToggle( {
-                                               step: function( now, tween ) {
-                                                       self._trigger( 
'animationstep', null, [ now, tween ] );
+
+                                       
self.options.$subject.stop().animateWithEvent(
+                                               'togglerstatetransition',
+                                               'slideToggle',
+                                               function( animationEvent ) {
+                                                       self._trigger( 
'animation', animationEvent );
                                                }
-                                       } );
+                                       );
                                }
                        } )
                        .on( 'mouseover.' + this.widgetName, function( event ) {
@@ -151,13 +151,17 @@
                                makeVisible = !makeVisible;
                        }
                        // Add classes displaying rotated icon. If CSS3 
transform is available, use it:
-                       this.$toggleIcon.removeClass( CLS_TOGGLE_HIDDEN + ' ' + 
this.widgetBaseClass + '-icon3dtrans ' + CLS_TOGGLE_VISIBLE );
+                       this.$toggleIcon.removeClass( CLS_TOGGLE_HIDDEN + ' ' + 
CLS_TOGGLE_VISIBLE + ' '
+                               + this.widgetBaseClass + '-icon3dtrans' );
+
                        if( !browserSupportsTransform ) {
                                this.$toggleIcon.addClass( makeVisible ? 
CLS_TOGGLE_VISIBLE : CLS_TOGGLE_HIDDEN );
                        } else {
-                               this.$toggleIcon.addClass( this.widgetBaseClass 
+ '-icon3dtrans ' + CLS_TOGGLE_VISIBLE );
+                               this.$toggleIcon.addClass(
+                                       this.widgetBaseClass + '-icon3dtrans ' 
+ CLS_TOGGLE_VISIBLE );
                        }
-                       this.element[ makeVisible ? 'removeClass' : 'addClass' 
]( this.widgetBaseClass + '-toggle-collapsed' );
+                       this.element[ makeVisible ? 'removeClass' : 'addClass' 
](
+                               this.widgetBaseClass + '-toggle-collapsed' );
                },
 
                /**
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
index 78f2c67..13c47dd 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.GlobeCoordinateInput.js
@@ -79,12 +79,13 @@
                        } )
                        .appendTo( this.$viewPort )
                        .eachchange( function( event, oldValue ) {
-                               this._viewNotifier.notify( 'change' );
+                               self._viewNotifier.notify( 'change' );
                        } )
                        .inputextender( {
                                initCallback: function( $extension ) {
                                        self._initInputExtender( $extension );
-                               }
+                               },
+                               contentAnimationEvents: 'toggleranimation'
                        } );
                },
 
@@ -187,6 +188,8 @@
                                inputExtender.destroy();
                        }
 
+                       this.$input.off( 'eachchange' );
+
                        this.$input = null;
                        this.$precision = null;
                        this.$precisionContainer = null;
diff --git 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
index 0ea0e56..9f181b6 100644
--- 
a/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
+++ 
b/ValueView/resources/jquery.valueview/valueview.experts/experts.TimeInput.js
@@ -112,7 +112,8 @@
                        .inputextender( {
                                initCallback: function( $extension ) {
                                        self._initInputExtender( $extension );
-                               }
+                               },
+                               contentAnimationEvents: 'toggleranimation'
                        } )
                        .on( 'timeinputupdate.' + this.uiBaseClass, function( 
event, value ) {
                                self._updateCalendarHint( value );
diff --git a/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js 
b/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
index 717ee14..237b05a 100644
--- a/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
+++ b/ValueView/tests/qunit/jquery.ui/jquery.ui.inputextender.tests.js
@@ -57,7 +57,8 @@
         *        after the promise got resolved. If the promise gets rejected, 
then the hide action
         *        will never be performed.
         * @param {Object} callbacks
-        * @return {jQuery.Promise} resolved after final hiding is done.
+        * @return {jQuery.Promise} Resolved after final hiding is done. Can be 
rejected in case a
+        *         hideControl has been injected and gets rejected.
         */
        function showAndHideExtensionAgain( instance, hideControl, callbacks ) {
                var deferred = $.Deferred();
@@ -81,6 +82,9 @@
 
                                QUnit.stop(); // wait for hideExtension() 
callback *2*
                        } )
+                       .fail( function() {
+                               deferred.reject();
+                       } )
                        .always( function() {
                                QUnit.start(); // *1*
                        } );
@@ -95,8 +99,9 @@
        QUnit.module( 'jquery.ui.inputextender', {
                teardown: function() {
                        $( '.test_inputextender' ).each( function( i, node ) {
-                               if( $( node ).data( 'inputextender' ) ) {
-                                       $( node ).data( 'inputextender' 
).destroy();
+                               var inputextender = $( node ).data( 
'inputextender' );
+                               if( inputextender ) {
+                                       inputextender.destroy();
                                }
                                $( node ).remove();
                        } );
@@ -106,9 +111,8 @@
        QUnit.test( 'Initialization', 2, function( assert ) {
                var extender = newTestInputextender();
 
-               assert.equal(
-                       $( '.test_inputextender' ).data( 'inputextender' ),
-                       extender,
+               assert.ok(
+                       extender instanceof $.ui.inputextender,
                        'Initialized widget.'
                );
 
@@ -132,6 +136,7 @@
                var extender = newTestInputextender(),
                        widgetBaseClass = extender.widgetBaseClass;
 
+               extender.showExtension(); // Make sure extension is being 
constructed.
                extender.destroy();
 
                assert.ok(

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: If57ee1eea13d1d016915b8e06b8e9cea05c63b5e
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <[email protected]>

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

Reply via email to