Accordion: Add classes option

Ref #7053
Ref gh-1411
This commit is contained in:
Alexander Schmitz 2014-12-03 11:23:19 -05:00
parent c192d4086d
commit 7c6a7d71e9
4 changed files with 81 additions and 69 deletions

View File

@ -9,6 +9,7 @@
<script src="../../../external/qunit/qunit.js"></script> <script src="../../../external/qunit/qunit.js"></script>
<script src="../../../external/jquery-simulate/jquery.simulate.js"></script> <script src="../../../external/jquery-simulate/jquery.simulate.js"></script>
<script src="../testsuite.js"></script> <script src="../testsuite.js"></script>
<script src="../../../external/qunit-assert-classes/qunit-assert-classes.js"></script>
<script> <script>
TestHelpers.loadResources({ TestHelpers.loadResources({
css: [ "core", "accordion" ], css: [ "core", "accordion" ],

View File

@ -2,7 +2,11 @@ TestHelpers.commonWidgetTests( "accordion", {
defaults: { defaults: {
active: 0, active: 0,
animate: {}, animate: {},
classes: {}, classes: {
"ui-accordion-header": "ui-corner-top",
"ui-accordion-header-collapsed": "ui-corner-all",
"ui-accordion-content": "ui-corner-bottom"
},
collapsible: false, collapsible: false,
disabled: false, disabled: false,
event: "click", event: "click",

View File

@ -6,14 +6,26 @@ var setupTeardown = TestHelpers.accordion.setupTeardown,
module( "accordion: core", setupTeardown() ); module( "accordion: core", setupTeardown() );
$.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" }, function( type, selector ) { $.each( { div: "#list1", ul: "#navigation", dl: "#accordion-dl" }, function( type, selector ) {
test( "markup structure: " + type, function() {
expect( 4 ); test( "markup structure: " + type, function( assert ) {
var element = $( selector ).accordion(); expect( 10 );
ok( element.hasClass( "ui-accordion" ), "main element is .ui-accordion" ); var element = $( selector ).accordion(),
equal( element.find( ".ui-accordion-header" ).length, 3, headers = element.find( ".ui-accordion-header" ),
".ui-accordion-header elements exist, correct number" ); content = headers.next();
equal( element.find( ".ui-accordion-content" ).length, 3,
".ui-accordion-content elements exist, correct number" ); assert.hasClasses( element, "ui-accordion ui-widget" );
equal( headers.length, 3, ".ui-accordion-header elements exist, correct number" );
assert.hasClasses( headers[ 0 ],
"ui-accordion-header ui-accordion-header-active ui-accordion-icons" );
assert.hasClasses( headers[ 1 ],
"ui-accordion-header ui-accordion-header-collapsed ui-accordion-icons" );
assert.hasClasses( headers[ 2 ],
"ui-accordion-header ui-accordion-header-collapsed ui-accordion-icons" );
equal( content.length, 3, ".ui-accordion-content elements exist, correct number" );
assert.hasClasses( content[ 0 ],
"ui-accordion-content ui-widget-content ui-accordion-content-active" );
assert.hasClasses( content[ 1 ], "ui-accordion-content ui-widget-content" );
assert.hasClasses( content[ 2 ], "ui-accordion-content ui-widget-content" );
deepEqual( element.find( ".ui-accordion-header" ).next().get(), deepEqual( element.find( ".ui-accordion-header" ).next().get(),
element.find( ".ui-accordion-content" ).get(), element.find( ".ui-accordion-content" ).get(),
"content panels come immediately after headers" ); "content panels come immediately after headers" );

View File

@ -37,6 +37,11 @@ return $.widget( "ui.accordion", {
options: { options: {
active: 0, active: 0,
animate: {}, animate: {},
classes: {
"ui-accordion-header": "ui-corner-top",
"ui-accordion-header-collapsed": "ui-corner-all",
"ui-accordion-content": "ui-corner-bottom"
},
collapsible: false, collapsible: false,
event: "click", event: "click",
header: "> li > :first-child,> :not(li):even", header: "> li > :first-child,> :not(li):even",
@ -69,10 +74,10 @@ return $.widget( "ui.accordion", {
_create: function() { _create: function() {
var options = this.options; var options = this.options;
this.prevShow = this.prevHide = $(); this.prevShow = this.prevHide = $();
this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
// ARIA this.element.attr( "role", "tablist" );
.attr( "role", "tablist" );
// don't allow collapsible: false and active: false / null // don't allow collapsible: false and active: false / null
if ( !options.collapsible && (options.active === false || options.active == null) ) { if ( !options.collapsible && (options.active === false || options.active == null) ) {
@ -95,37 +100,33 @@ return $.widget( "ui.accordion", {
}, },
_createIcons: function() { _createIcons: function() {
var icons = this.options.icons; var icon, children,
icons = this.options.icons;
if ( icons ) { if ( icons ) {
$( "<span>" ) icon = $( "<span>" );
.addClass( "ui-accordion-header-icon ui-icon " + icons.header ) this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
.prependTo( this.headers ); icon.prependTo( this.headers );
this.active.children( ".ui-accordion-header-icon" ) children = this.active.children( ".ui-accordion-header-icon" );
.removeClass( icons.header ) this._removeClass( children, icons.header )
.addClass( icons.activeHeader ); ._addClass( children, null, icons.activeHeader )
this.headers.addClass( "ui-accordion-icons" ); ._addClass( this.headers, "ui-accordion-icons" );
} }
}, },
_destroyIcons: function() { _destroyIcons: function() {
this.headers this._removeClass( this.headers, "ui-accordion-icons" );
.removeClass( "ui-accordion-icons" ) this.headers.children( ".ui-accordion-header-icon" ).remove();
.children( ".ui-accordion-header-icon" )
.remove();
}, },
_destroy: function() { _destroy: function() {
var contents; var contents;
// clean up main element // clean up main element
this.element this.element.removeAttr( "role" );
.removeClass( "ui-accordion ui-widget ui-helper-reset" )
.removeAttr( "role" );
// clean up headers // clean up headers
this.headers this.headers
.removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
"ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
.removeAttr( "role" ) .removeAttr( "role" )
.removeAttr( "aria-expanded" ) .removeAttr( "aria-expanded" )
.removeAttr( "aria-selected" ) .removeAttr( "aria-selected" )
@ -137,8 +138,6 @@ return $.widget( "ui.accordion", {
// clean up content panels // clean up content panels
contents = this.headers.next() contents = this.headers.next()
.removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
"ui-accordion-content ui-accordion-content-active ui-state-disabled" )
.css( "display", "" ) .css( "display", "" )
.removeAttr( "role" ) .removeAttr( "role" )
.removeAttr( "aria-hidden" ) .removeAttr( "aria-hidden" )
@ -178,14 +177,15 @@ return $.widget( "ui.accordion", {
} }
} }
// #5332 - opacity doesn't cascade to positioned elements in IE // Support: IE8 Only
// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
// so we need to add the disabled class to the headers and panels // so we need to add the disabled class to the headers and panels
if ( key === "disabled" ) { if ( key === "disabled" ) {
this.element this.element.attr( "aria-disabled", value );
.toggleClass( "ui-state-disabled", !!value )
.attr( "aria-disabled", value ); this._toggleClass( null, "ui-state-disabled", !!value );
this.headers.add( this.headers.next() ) this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
.toggleClass( "ui-state-disabled", !!value ); !!value );
} }
}, },
@ -270,13 +270,12 @@ return $.widget( "ui.accordion", {
var prevHeaders = this.headers, var prevHeaders = this.headers,
prevPanels = this.panels; prevPanels = this.panels;
this.headers = this.element.find( this.options.header ) this.headers = this.element.find( this.options.header );
.addClass( "ui-accordion-header ui-state-default ui-corner-all" ); this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
"ui-state-default" );
this.panels = this.headers.next() this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
.addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
.filter( ":not(.ui-accordion-content-active)" )
.hide();
// Avoid memory leaks (#10056) // Avoid memory leaks (#10056)
if ( prevPanels ) { if ( prevPanels ) {
@ -291,12 +290,11 @@ return $.widget( "ui.accordion", {
heightStyle = options.heightStyle, heightStyle = options.heightStyle,
parent = this.element.parent(); parent = this.element.parent();
this.active = this._findActive( options.active ) this.active = this._findActive( options.active );
.addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
.removeClass( "ui-corner-all" ); ._removeClass( this.active, "ui-accordion-header-collapsed" );
this.active.next() this._addClass( this.active.next(), "ui-accordion-content-active" );
.addClass( "ui-accordion-content-active" ) this.active.next().show();
.show();
this.headers this.headers
.attr( "role", "tab" ) .attr( "role", "tab" )
@ -415,7 +413,8 @@ return $.widget( "ui.accordion", {
}, },
_eventHandler: function( event ) { _eventHandler: function( event ) {
var options = this.options, var activeChildren, clickedChildren,
options = this.options,
active = this.active, active = this.active,
clicked = $( event.currentTarget ), clicked = $( event.currentTarget ),
clickedIsActive = clicked[ 0 ] === active[ 0 ], clickedIsActive = clicked[ 0 ] === active[ 0 ],
@ -448,26 +447,23 @@ return $.widget( "ui.accordion", {
// switch classes // switch classes
// corner classes on the previously active header stay after the animation // corner classes on the previously active header stay after the animation
active.removeClass( "ui-accordion-header-active ui-state-active" ); this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
if ( options.icons ) { if ( options.icons ) {
active.children( ".ui-accordion-header-icon" ) activeChildren = active.children( ".ui-accordion-header-icon" );
.removeClass( options.icons.activeHeader ) this._removeClass( activeChildren, null, options.icons.activeHeader )
.addClass( options.icons.header ); ._addClass( activeChildren, null, options.icons.header );
} }
if ( !clickedIsActive ) { if ( !clickedIsActive ) {
clicked this._removeClass( clicked, "ui-accordion-header-collapsed" )
.removeClass( "ui-corner-all" ) ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
.addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
if ( options.icons ) { if ( options.icons ) {
clicked.children( ".ui-accordion-header-icon" ) clickedChildren = clicked.children( ".ui-accordion-header-icon" );
.removeClass( options.icons.header ) this._removeClass( clickedChildren, null, options.icons.header )
.addClass( options.icons.activeHeader ); ._addClass( clickedChildren, null, options.icons.activeHeader );
} }
clicked this._addClass( clicked.next(), "ui-accordion-content-active" );
.next()
.addClass( "ui-accordion-content-active" );
} }
}, },
@ -579,13 +575,12 @@ return $.widget( "ui.accordion", {
}, },
_toggleComplete: function( data ) { _toggleComplete: function( data ) {
var toHide = data.oldPanel; var toHide = data.oldPanel,
prev = toHide.prev();
toHide this._removeClass( toHide, "ui-accordion-content-active" );
.removeClass( "ui-accordion-content-active" ) this._removeClass( prev, "ui-accordion-header-active" )
.prev() ._addClass( prev, "ui-accordion-header-collapsed" );
.removeClass( "ui-corner-top" )
.addClass( "ui-corner-all" );
// Work around for rendering bug in IE (#5421) // Work around for rendering bug in IE (#5421)
if ( toHide.length ) { if ( toHide.length ) {