From 2d95d36a8ed296813e686e9b756c2bb7c306950f Mon Sep 17 00:00:00 2001 From: Moritz Oberhauser Date: Thu, 6 Apr 2017 12:43:18 +0200 Subject: [PATCH] Allow more customization on the default toggle system The naming convention remains unchainched. Default toggles are added if no mw-collapsible-toggle child element is present. Premade toggles have already one ore more mw-collapsible-toggle elements defined. Default and premade toggles (mw-collapsible-toggle) still cannot be mixed/combined with remote toggles (mw-customtoggle). * The default toggle got less rigid by removing dependency on elements. * Support for multiple premade toggles was introduced. * The expand/collapse messages can be used by premade toggles via mw-collapsible-text. * Removed the linksPassthru option. This step allowed merging premadeToggleHandler into actionHandler. * The pass through functionality is now applied to all elements since the default toggle does no longer depends on those. * Removed mw-collapsible-bracket because it was not used and is deprecated by mw-collapsible-text. * The test suite was adapted to reflect the latest changes. Change-Id: Ic8627c4c185e8e4175e6fef1c8e1c2190e54edaa --- .../src/jquery/jquery.makeCollapsible.js | 53 ++++++------------- .../jquery/jquery.makeCollapsible.test.js | 43 ++++++++++++--- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/resources/src/jquery/jquery.makeCollapsible.js b/resources/src/jquery/jquery.makeCollapsible.js index 7296811e31..9d3df8cbf3 100644 --- a/resources/src/jquery/jquery.makeCollapsible.js +++ b/resources/src/jquery/jquery.makeCollapsible.js @@ -35,12 +35,6 @@ if ( $defaultToggle === undefined ) { $defaultToggle = null; } - if ( $defaultToggle !== null && !$defaultToggle.jquery ) { - // is optional (may be undefined), but if defined it must be an instance of jQuery. - // If it's not, abort right away. - // After this $defaultToggle is either null or a valid jQuery instance. - 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 @@ -158,12 +152,9 @@ if ( e ) { if ( e.type === 'click' && - options.linksPassthru && - e.target.nodeName.toLowerCase() === 'a' && - $( e.target ).attr( 'href' ) && - $( e.target ).attr( 'href' ) !== '#' + e.target.nodeName.toLowerCase() === 'a' ) { - // Don't fire if a link with href !== '#' was clicked, if requested (for premade togglers by default) + // Don't fire if a link was clicked (for premade togglers) return; } else if ( e.type === 'keypress' && e.which !== 13 && e.which !== 32 ) { // Only handle keypresses on the "Enter" or "Space" keys @@ -191,16 +182,15 @@ .toggleClass( 'mw-collapsible-toggle-expanded', wasCollapsed ); } - // Toggle the text ("Show"/"Hide"), if requested (for default togglers by default) + // Toggle the text ("Show"/"Hide") within elements tagged with mw-collapsible-text if ( options.toggleText ) { collapseText = options.toggleText.collapseText; expandText = options.toggleText.expandText; - $textContainer = $toggle.find( '> a' ); - if ( !$textContainer.length ) { - $textContainer = $toggle; + $textContainer = $collapsible.find( '.mw-collapsible-text' ); + if ( $textContainer.length ) { + $textContainer.text( wasCollapsed ? collapseText : expandText ); } - $textContainer.text( wasCollapsed ? collapseText : expandText ); } // And finally toggle the element state itself @@ -242,7 +232,7 @@ this.each( function () { var $collapsible, collapseText, expandText, $caption, $toggle, actionHandler, buildDefaultToggleLink, - premadeToggleHandler, $toggleLink, $firstItem, collapsibleId, $customTogglers, firstval; + $toggleLink, $firstItem, collapsibleId, $customTogglers, firstval; // Ensure class "mw-collapsible" is present in case .makeCollapsible() // is called on element(s) that don't have it yet. @@ -268,28 +258,21 @@ opts = $.extend( defaultOpts, options, opts ); togglingHandler( $( this ), $collapsible, e, opts ); }; + // Default toggle link. Only build it when needed to avoid jQuery memory leaks (event data). buildDefaultToggleLink = function () { - return $( '' ) - .attr( { - role: 'button', - tabindex: 0 - } ) + return $( '' ) .text( collapseText ) - .wrap( '' ) - .parent() - .prepend( '[' ) - .append( ']' ) + .wrap( '' ).parent() + .attr( { + role: 'button', + tabindex: 0 + } ) + .prepend( '[' ) + .append( ']' ) .on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler ); }; - // Default handler for clicking on premade toggles - premadeToggleHandler = function ( e, opts ) { - var defaultOpts = { toggleClasses: true, linksPassthru: true }; - opts = $.extend( defaultOpts, options, opts ); - togglingHandler( $( this ), $collapsible, e, opts ); - }; - // Check if this element has a custom position for the toggle link // (ie. outside the container or deeper inside the tree) if ( options.$customTogglers ) { @@ -331,7 +314,6 @@ if ( !$toggle.length ) { $toggleLink = buildDefaultToggleLink().appendTo( $caption ); } else { - actionHandler = premadeToggleHandler; $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler ) .prop( 'tabIndex', 0 ); } @@ -344,7 +326,6 @@ if ( !$toggle.length ) { $toggleLink = buildDefaultToggleLink().prependTo( $firstItem.eq( -1 ) ); } else { - actionHandler = premadeToggleHandler; $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler ) .prop( 'tabIndex', 0 ); } @@ -374,7 +355,6 @@ $toggleLink = buildDefaultToggleLink(); $toggleLink.wrap( '
  • ' ).parent().prependTo( $collapsible ); } else { - actionHandler = premadeToggleHandler; $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler ) .prop( 'tabIndex', 0 ); } @@ -393,7 +373,6 @@ if ( !$toggle.length ) { $toggleLink = buildDefaultToggleLink().prependTo( $collapsible ); } else { - actionHandler = premadeToggleHandler; $toggleLink = $toggle.on( 'click.mw-collapsible keypress.mw-collapsible', actionHandler ) .prop( 'tabIndex', 0 ); } diff --git a/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js b/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js index 4e77d72127..44a2305352 100644 --- a/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js +++ b/tests/qunit/suites/resources/jquery/jquery.makeCollapsible.test.js @@ -262,11 +262,11 @@ $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); } ); - QUnit.test( 'clicks on links inside toggler pass through (options.linksPassthru)', function ( assert ) { + QUnit.test( 'clicks on links inside toggler pass through', function ( assert ) { var $collapsible = prepareCollapsible( '
    ' + '
    ' + - 'Toggle toggle toggle toggle' + + 'Toggle toggle toggle toggle' + '
    ' + '
    ' + loremIpsum + '
    ' + '
    ', @@ -288,12 +288,12 @@ loremIpsum + '' ), - $toggleLink = $collapsible.find( '.mw-collapsible-toggle a' ); + $toggleText = $collapsible.find( '.mw-collapsible-text' ); - assert.equal( $toggleLink.text(), 'Collapse me!', 'data-collapsetext is respected' ); + assert.equal( $toggleText.text(), 'Collapse me!', 'data-collapsetext is respected' ); $collapsible.on( 'afterCollapse.mw-collapsible', function () { - assert.equal( $toggleLink.text(), 'Expand me!', 'data-expandtext is respected' ); + assert.equal( $toggleText.text(), 'Expand me!', 'data-expandtext is respected' ); } ); $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); @@ -304,12 +304,39 @@ '
    ' + loremIpsum + '
    ', { collapseText: 'Collapse me!', expandText: 'Expand me!' } ), - $toggleLink = $collapsible.find( '.mw-collapsible-toggle a' ); + $toggleText = $collapsible.find( '.mw-collapsible-text' ); - assert.equal( $toggleLink.text(), 'Collapse me!', 'options.collapseText is respected' ); + assert.equal( $toggleText.text(), 'Collapse me!', 'options.collapseText is respected' ); $collapsible.on( 'afterCollapse.mw-collapsible', function () { - assert.equal( $toggleLink.text(), 'Expand me!', 'options.expandText is respected' ); + assert.equal( $toggleText.text(), 'Expand me!', 'options.expandText is respected' ); + } ); + + $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); + } ); + + QUnit.test( 'predefined toggle button and text (.mw-collapsible-toggle/.mw-collapsible-text)', function ( assert ) { + var $collapsible = prepareCollapsible( + '
    ' + + '
    ' + + '[Toggle]' + + '
    ' + + '
    ' + loremIpsum + '
    ' + + '
    ', + { collapseText: 'Hide', expandText: 'Show' } + ), + $toggleText = $collapsible.find( '.mw-collapsible-text' ); + + assert.equal( $toggleText.text(), 'Toggle', 'predefined text remains' ); + + $collapsible.on( 'afterCollapse.mw-collapsible', function () { + assert.equal( $toggleText.text(), 'Show', 'predefined text is toggled' ); + + $collapsible.on( 'afterExpand.mw-collapsible', function () { + assert.equal( $toggleText.text(), 'Hide', 'predefined text is toggled back' ); + } ); + + $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); } ); $collapsible.find( '.mw-collapsible-toggle' ).trigger( 'click' ); -- 2.20.1