From a72eb7fd4261748009e8da94aad573afd80f95af Mon Sep 17 00:00:00 2001 From: MatmaRex Date: Sat, 23 Mar 2013 16:13:17 +0100 Subject: [PATCH] jquery.makeCollapsible: events for collapsing/expanding, tests Trigger a custom event to allow callers to hook to the collapsing/expanding, allowing the module to be testable and making it possible to e.g. implement persistence via cookies. Added tests for the triggers themselves and for some basic asynchronous collapsing functionality. The following four events are fired (the namespace used is the same one as the one used for firing the click event for initial toggle): * beforeExpand.mw-collapsible * beforeCollapse.mw-collapsible * afterExpand.mw-collapsible * afterCollapse.mw-collapsible Change-Id: I580365770d061418a6734fcb54b2d86f2a821748 --- resources/jquery/jquery.makeCollapsible.js | 34 ++++++--- .../jquery/jquery.makeCollapsible.test.js | 71 ++++++++++++++++++- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/resources/jquery/jquery.makeCollapsible.js b/resources/jquery/jquery.makeCollapsible.js index 3600c5d6d6..f07f1b7704 100644 --- a/resources/jquery/jquery.makeCollapsible.js +++ b/resources/jquery/jquery.makeCollapsible.js @@ -24,7 +24,7 @@ * @param {Object|undefined} options */ function toggleElement( $collapsible, action, $defaultToggle, options ) { - var $collapsibleContent, $containers; + var $collapsibleContent, $containers, hookCallback; options = options || {}; // Validate parameters @@ -47,6 +47,14 @@ return; } + // Trigger a custom event to allow callers to hook to the collapsing/expanding, + // allowing the module to be testable, and making it possible to + // e.g. implement persistence via cookies + $collapsible.trigger( action === 'expand' ? 'beforeExpand.mw-collapsible' : 'beforeCollapse.mw-collapsible' ); + hookCallback = function () { + $collapsible.trigger( action === 'expand' ? 'afterExpand.mw-collapsible' : 'afterCollapse.mw-collapsible' ); + }; + // Handle different kinds of elements if ( !options.plainMode && $collapsible.is( 'table' ) ) { @@ -63,11 +71,12 @@ // http://stackoverflow.com/questions/467336#920480 if ( options.instantHide ) { $containers.hide(); + hookCallback(); } else { - $containers.stop( true, true ).fadeOut(); + $containers.stop( true, true ).fadeOut( hookCallback ); } } else { - $containers.stop( true, true ).fadeIn(); + $containers.stop( true, true ).fadeIn( hookCallback ); } } else if ( !options.plainMode && ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) ) { @@ -81,11 +90,12 @@ if ( action === 'collapse' ) { if ( options.instantHide ) { $containers.hide(); + hookCallback(); } else { - $containers.stop( true, true ).slideUp(); + $containers.stop( true, true ).slideUp( hookCallback ); } } else { - $containers.stop( true, true ).slideDown(); + $containers.stop( true, true ).slideDown( hookCallback ); } } else { @@ -97,11 +107,12 @@ if ( action === 'collapse' ) { if ( options.instantHide ) { $collapsibleContent.hide(); + hookCallback(); } else { - $collapsibleContent.slideUp(); + $collapsibleContent.slideUp( hookCallback ); } } else { - $collapsibleContent.slideDown(); + $collapsibleContent.slideDown( hookCallback ); } // Otherwise assume this is a customcollapse with a remote toggle @@ -110,18 +121,19 @@ if ( action === 'collapse' ) { if ( options.instantHide ) { $collapsible.hide(); + hookCallback(); } else { if ( $collapsible.is( 'tr' ) || $collapsible.is( 'td' ) || $collapsible.is( 'th' ) ) { - $collapsible.fadeOut(); + $collapsible.fadeOut( hookCallback ); } else { - $collapsible.slideUp(); + $collapsible.slideUp( hookCallback ); } } } else { if ( $collapsible.is( 'tr' ) || $collapsible.is( 'td' ) || $collapsible.is( 'th' ) ) { - $collapsible.fadeIn(); + $collapsible.fadeIn( hookCallback ); } else { - $collapsible.slideDown(); + $collapsible.slideDown( hookCallback ); } } } diff --git a/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js b/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js index 082d86b451..9f34beee95 100644 --- a/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js @@ -10,6 +10,59 @@ .makeCollapsible( options ); } + QUnit.asyncTest( 'testing hooks (triggers)', 4, function ( assert ) { + var $collapsible, $content, $toggle; + $collapsible = prepareCollapsible( + '
' + loremIpsum + '
' + ); + $content = $collapsible.find( '.mw-collapsible-content' ); + $toggle = $collapsible.find( '.mw-collapsible-toggle' ); + + // In one full collapse-expand cycle, each event will be fired once + + // On collapse... + $collapsible.on( 'beforeCollapse.mw-collapsible', function () { + assert.assertTrue( $content.is( ':visible' ), 'first beforeCollapseExpand: content is visible' ); + } ); + $collapsible.on( 'afterCollapse.mw-collapsible', function () { + assert.assertTrue( $content.is( ':hidden' ), 'first afterCollapseExpand: content is hidden' ); + + // On expand... + $collapsible.on( 'beforeExpand.mw-collapsible', function () { + assert.assertTrue( $content.is( ':hidden' ), 'second beforeCollapseExpand: content is hidden' ); + } ); + $collapsible.on( 'afterExpand.mw-collapsible', function () { + assert.assertTrue( $content.is( ':visible' ), 'second afterCollapseExpand: content is visible' ); + + QUnit.start(); + } ); + + // ...expanding happens here + $toggle.trigger( 'click' ); + } ); + + // ...collapsing happens here + $toggle.trigger( 'click' ); + } ); + + QUnit.asyncTest( 'basic operation', 3, function ( assert ) { + var $collapsible, $content; + $collapsible = prepareCollapsible( + '
' + loremIpsum + '
' + ); + $content = $collapsible.find( '.mw-collapsible-content' ); + + assert.equal( $content.length, 1, 'content is present' ); + assert.assertTrue( $content.is( ':visible' ), 'content is visible' ); + + $collapsible.on( 'afterCollapse.mw-collapsible', function () { + assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' ); + QUnit.start(); + } ); + + $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); + } ); + QUnit.test( 'basic operation with instantHide (synchronous test)', 2, function ( assert ) { var $collapsible, $content; $collapsible = prepareCollapsible( @@ -25,7 +78,7 @@ assert.assertTrue( $content.is( ':hidden' ), 'after collapsing: content is hidden' ); } ); - QUnit.test( 'initially collapsed - mw-collapsed class', 1, function ( assert ) { + QUnit.asyncTest( 'initially collapsed - mw-collapsed class', 2, function ( assert ) { var $collapsible, $content; $collapsible = prepareCollapsible( '
' + loremIpsum + '
' @@ -34,9 +87,16 @@ // Synchronous - mw-collapsed should cause instantHide: true to be used on initial collapsing assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' ); + + $collapsible.on( 'afterExpand.mw-collapsible', function () { + assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' ); + QUnit.start(); + } ); + + $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); } ); - QUnit.test( 'initially collapsed - options', 1, function ( assert ) { + QUnit.asyncTest( 'initially collapsed - options', 2, function ( assert ) { var $collapsible, $content; $collapsible = prepareCollapsible( '
' + loremIpsum + '
', @@ -46,6 +106,13 @@ // Synchronous - collapsed: true should cause instantHide: true to be used on initial collapsing assert.assertTrue( $content.is( ':hidden' ), 'content is hidden' ); + + $collapsible.on( 'afterExpand.mw-collapsible', function () { + assert.assertTrue( $content.is( ':visible' ), 'after expanding: content is visible' ); + QUnit.start(); + } ); + + $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); } ); }( mediaWiki, jQuery ) ); -- 2.20.1