* @param {Object|undefined} options
*/
function toggleElement( $collapsible, action, $defaultToggle, options ) {
- var $collapsibleContent, $containers;
+ var $collapsibleContent, $containers, hookCallback;
options = options || {};
// Validate parameters
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' ) ) {
// 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' ) ) ) {
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 {
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
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 );
}
}
}
.makeCollapsible( options );
}
+ QUnit.asyncTest( 'testing hooks (triggers)', 4, function ( assert ) {
+ var $collapsible, $content, $toggle;
+ $collapsible = prepareCollapsible(
+ '<div class="mw-collapsible">' + loremIpsum + '</div>'
+ );
+ $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(
+ '<div class="mw-collapsible">' + loremIpsum + '</div>'
+ );
+ $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(
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(
'<div class="mw-collapsible mw-collapsed">' + loremIpsum + '</div>'
// 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(
'<div class="mw-collapsible">' + loremIpsum + '</div>',
// 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 ) );