Sorting accordion sections
Using the sortable interaction widget, we're able to transform a static accordion section layout into something specified by the user. That is, sortable interaction widgets take a container element, and allow all child elements to be sorted in place. The user does this by dragging the element to the desired order.
We'll look at how we can extend the accordion capabilities so that the sortable section functionality is encapsulated, and can be switched on by a configuration option at the time of creation.
How to do it...
We have to perform several actions when the accordion widget is created, and when the accordion is destroyed. Here is how we extend the widget:
( function( $, undefined ) { $.widget( "ab.accordion", $.ui.accordion, { options: { sortable: false }, _create: function () { this._super( "_create" ); if ( !this.options.sortable ) { return; } this.headers.each( function() { $( this ).next() .addBack() .wrapAll( "<div/>" ); }); this.element.sortable({ axis: "y", handle: "h3", stop: function( event, ui ) { ui.item.children( "h3" ) .triggerHandler( "focusout" ); } }); }, _destroy: function () { if ( !this.options.sortable ) { this._super( "_destroy" ); return; } this.element.sortable( "destroy" ); this.headers.each( function () { $( this ).unwrap( "<div/>" ); }); this._super( "_destroy" ); } }); })( jQuery ); $( function() { $( "#accordion" ).accordion( { sortable: true } ); });
With our new accordion widget marked as sortable
, users now have the ability to drag header sections around within the accordion. For instance, if the first accordion section belongs to the bottom, the user just drags it to the bottom.
How it works...
With the help of the sortable()
interaction widget, we're able to extend the default accordion widget implementation to include sorting capabilities. As with any jQuery UI widget enhancements, we don't actually need to extend the widget in question; the new capabilities can always be tacked-on after the widget has been instantiated. However, as you'll see throughout this book, the best practice is to encapsulate customizations and present them to the widget client as a set of options.
Here, we've extended the set of available accordion options to include a sortable
option. This is how we turn our customization on or off (it is a boolean value). The customized version of _create()
that we've implemented will call the default version of the accordion's _create()
method. Afterward, we'll see if the sortable behavior is turned off (in which case we have nothing to do, and so return). Likewise, our custom _delete()
function checks if the sortable behavior has been turned on after calling the original delete functionality.
The tricky part of implementing sortable accordion sections is the fact that we have to make a slight DOM manipulation inside the accordion element. This is necessary in order to use the sortable interaction widget. Accordion widget markup is structured such that all sections are adjacent to one another. That is, we have an h3
element, followed by a div
element. This is one section, and is followed by another h3
and another div
, and so on. It is a flat structure. There are two ways to deal with this: alter the markup required to create the widget, or inject some slight DOM modifications, and the widget client is none-the-wiser. We're going the latter route and not requiring the client to change their code. This is another best practice, to keep the existing widget client code functional when providing customizations.
In our customized version of _create()
, we're iterating over each accordion header and wrapping the header element and the corresponding content element in a div
element so as to bundle them together. This way, the sortable widget knows how to move this bundle around. Had we not done this, the user would only be able to move the header section, thus severing it from its content. Finally, we're creating the sortable widget, restricting movement to the y-axis and setting the movable handle as the accordion header.
Our customized _destroy()
function undoes our modifications before calling the original _destroy()
method. This entails unwrapping our new div
element and destroying the sortable widget.