Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.

Commit 17d7b77

Browse files
author
Gabriel Schulhof
committed
Collapsible: Make _setOptions work with possible inheritance from an accordion.
1 parent fc29d74 commit 17d7b77

File tree

1 file changed

+137
-68
lines changed

1 file changed

+137
-68
lines changed

js/widgets/collapsible.js

Lines changed: 137 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -13,99 +13,59 @@ define( [
1313
//>>excludeEnd("jqmBuildExclude");
1414
(function( $, undefined ) {
1515

16-
var getAttr = $.mobile.getAttribute;
16+
var rInitialLetter = /([A-Z])/g;
1717

1818
$.widget( "mobile.collapsible", {
1919
options: {
20-
expandCueText: " click to expand contents",
21-
collapseCueText: " click to collapse contents",
20+
expandCueText: null,
21+
collapseCueText: null,
2222
collapsed: true,
2323
heading: "h1,h2,h3,h4,h5,h6,legend",
24-
collapsedIcon: "plus",
25-
expandedIcon: "minus",
26-
iconpos: "left",
24+
collapsedIcon: null,
25+
expandedIcon: null,
26+
iconpos: null,
2727
theme: null,
2828
contentTheme: null,
29-
inset: true,
30-
corners: true,
31-
mini: false
29+
inset: null,
30+
corners: null,
31+
mini: null
3232
},
3333

3434
_create: function() {
35-
var $el = this.element.addClass( "ui-collapsible" ),
35+
var anchor,
36+
$el = this.element.addClass( "ui-collapsible" ),
3637
opts = this.options,
3738
heading = $el.children( opts.heading ).first(),
3839
replacementHeading = heading,
3940
content = $el.wrapInner( "<div class='ui-collapsible-content'></div>" ).children( ".ui-collapsible-content" ),
40-
set = $el.closest( ":jqmData(role='collapsible-set')" + ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" : "" ) ).addClass( "ui-collapsible-set" ),
41-
classes = "";
42-
43-
// If we are in a collapsible set
44-
if ( set.length ) {
45-
46-
// Inherit the content-theme from collapsible-set
47-
if ( !opts.contentTheme ) {
48-
opts.contentTheme = getAttr( set[ 0 ], "content-theme", true );
49-
}
50-
51-
// Get the preference for collapsed icon in the set, but override with data- attribute on the individual collapsible
52-
opts.collapsedIcon = getAttr( $el[ 0 ], "collapsed-icon", true ) || getAttr( set[ 0 ], "collapsed-icon", true ) || opts.collapsedIcon;
53-
54-
// Get the preference for expanded icon in the set, but override with data- attribute on the individual collapsible
55-
opts.expandedIcon = getAttr( $el[ 0 ], "expanded-icon", true ) || getAttr( set[ 0 ], "expanded-icon", true ) || opts.expandedIcon;
56-
57-
// Gets the preference icon position in the set, but override with data- attribute on the individual collapsible
58-
opts.iconpos = getAttr( $el[ 0 ], "iconpos", true ) || getAttr( set[ 0 ], "iconpos", true ) || opts.iconpos;
59-
60-
// Inherit the preference for inset from collapsible-set or set the default value to ensure equalty within a set
61-
if ( getAttr( set[ 0 ], "inset", true ) !== undefined ) {
62-
opts.inset = getAttr( set[ 0 ], "inset", true );
63-
} else {
64-
opts.inset = true;
65-
}
66-
// Set corners for individual collapsibles to false when in a collapsible-set
67-
opts.corners = false;
68-
// Gets the preference for mini in the set
69-
if ( !opts.mini ) {
70-
opts.mini = getAttr( set[ 0 ], "mini", true );
71-
}
72-
}
73-
74-
if ( !!opts.inset ) {
75-
classes += " ui-collapsible-inset";
76-
if ( !!opts.corners ) {
77-
classes += " ui-corner-all" ;
78-
}
79-
}
80-
if ( opts.contentTheme ) {
81-
classes += " ui-collapsible-themed-content";
82-
content.addClass( "ui-body-" + opts.contentTheme );
83-
}
84-
if ( classes !== "" ) {
85-
$el.addClass( classes );
86-
}
41+
accordion = $el.closest( ":jqmData(role='collapsible-set')" + ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" : "" ) ).addClass( "ui-collapsible-set" );
8742

8843
// Replace collapsibleHeading if it's a legend
8944
if ( heading.is( "legend" ) ) {
9045
replacementHeading = $( "<div role='heading'>"+ heading.html() +"</div>" );
9146
heading.remove();
9247
}
9348

94-
replacementHeading
49+
anchor = replacementHeading
9550
//modify markup & attributes
9651
.addClass( "ui-collapsible-heading" )
9752
.append( "<span class='ui-collapsible-heading-status'></span>" )
9853
.wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
9954
.find( "a" )
10055
.first()
101-
.addClass( "ui-btn ui-icon-" + opts.collapsedIcon + " ui-btn-icon-" + opts.iconpos +
102-
( opts.theme ? " ui-btn-" + opts.theme : "" ) +
103-
( opts.mini ? " ui-mini" : "" ) );
56+
.addClass( "ui-btn" );
10457

10558
//drop heading in before content
10659
replacementHeading.insertBefore( content );
10760

10861
$.extend( this, {
62+
_accordion: accordion,
63+
_accordionWidget: null,
64+
_anchorClasses: "",
65+
_elClasses: "",
66+
_contentTheme: "",
67+
_anchor: anchor,
68+
_content: content,
10969
_collapsibleHeading: heading,
11070
_collapsibleContent: content
11171
});
@@ -136,10 +96,16 @@ $.widget( "mobile.collapsible", {
13696
},
13797

13898
_handleExpandCollapse: function( event ) {
139-
var isCollapse,
140-
opts = this.options;
99+
var isCollapse, key, opts;
141100

142101
if ( !event.isDefaultPrevented() ) {
102+
opts = $.extend( {}, this.options );
103+
104+
// Adjust for inherited values.
105+
for ( key in opts ) {
106+
opts[ key ] = this._optionValue( opts, key );
107+
}
108+
143109
isCollapse = ( event.type === "collapse" );
144110

145111
event.preventDefault();
@@ -151,6 +117,7 @@ $.widget( "mobile.collapsible", {
151117
.end()
152118
.find( "a" ).first()
153119
.toggleClass( "ui-icon-" + opts.expandedIcon, !isCollapse )
120+
154121
// logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
155122
.toggleClass( "ui-icon-" + opts.collapsedIcon, ( isCollapse || opts.expandedIcon === opts.collapsedIcon ) )
156123
.removeClass( $.mobile.activeBtnClass );
@@ -163,17 +130,119 @@ $.widget( "mobile.collapsible", {
163130
}
164131
},
165132

166-
_setOptions: function( opts ) {
167-
var $el = this.element;
133+
_toggleClasses: function( destination, varForOld, newClasses ) {
134+
if ( this[ varForOld ] !== newClasses ) {
135+
if ( this[ varForOld ] ) {
136+
destination.removeClass( this[ varForOld ] );
137+
this[ varForOld ] = "";
138+
}
139+
140+
if ( newClasses ) {
141+
this[ varForOld ] = newClasses;
142+
destination.addClass( this[ varForOld ] );
143+
}
144+
}
145+
return this;
146+
},
147+
148+
// Retrieve the option value first from the options object passed in and, if
149+
// null, from the parent accordion or, if that's null too, or if there's no
150+
// parent accordion, then from the defaults.
151+
_optionValue: function( options, name ) {
152+
var ret,
153+
accordion = this._accordion,
154+
accordionWidget = this._accordionWidget;
155+
156+
if ( accordion.length && !accordionWidget ) {
157+
this._accordionWidget = accordionWidget = accordion.data( "mobile-collapsibleset" );
158+
}
159+
160+
ret =
161+
( options[ name ] != null ) ? options[ name ] :
162+
( accordionWidget ) ? accordionWidget.options[ name ] :
163+
accordion.length ? $.mobile.getAttribute( accordion[ 0 ], name.replace( rInitialLetter, "-$1" ).toLowerCase(), true ):
164+
null;
165+
166+
if ( null == ret ) {
167+
ret = $.mobile.collapsible.defaults[ name ];
168+
}
169+
170+
return ret;
171+
},
172+
173+
_setOptions: function( options ) {
174+
var key,
175+
opts = $.extend( {}, this.options, options ),
176+
$el = this.element,
177+
classes = "",
178+
anchorClasses = "";
179+
180+
// Override inheritable options from the accordion or from defaults if
181+
// unset in this widget
182+
for ( key in opts ) {
183+
opts[ key ] = this._optionValue( opts, key );
184+
}
185+
186+
// Set corners for individual collapsibles to false when in a collapsible-set
187+
if ( this._accordion.length > 0 ) {
188+
opts.corners = false;
189+
}
190+
191+
if ( opts.contentTheme === "none" ) {
192+
opts.contentTheme = "";
193+
}
168194

169-
if ( opts.collapsed !== undefined ) {
170-
$el.trigger( opts.collapsed ? "collapse" : "expand" );
195+
if ( options.collapsed !== undefined ) {
196+
$el.trigger( options.collapsed ? "collapse" : "expand" );
171197
}
172198

173-
return this._super( opts );
199+
// Establish classes for outermost element
200+
if ( !!opts.inset ) {
201+
classes += " ui-collapsible-inset";
202+
if ( !!opts.corners ) {
203+
classes += " ui-corner-all" ;
204+
}
205+
}
206+
if ( opts.contentTheme ) {
207+
classes += " ui-collapsible-themed-content";
208+
}
209+
210+
// Establish classes for anchor
211+
if ( $el.hasClass( "ui-collapsible-collapsed" ) ) {
212+
anchorClasses += " ui-icon-" + opts.collapsedIcon;
213+
} else {
214+
anchorClasses += " ui-icon-" + opts.expandedIcon;
215+
}
216+
anchorClasses += " ui-btn-icon-" + opts.iconpos;
217+
if ( opts.theme ) {
218+
anchorClasses += " ui-btn-" + opts.theme;
219+
}
220+
if ( opts.mini ) {
221+
anchorClasses += " ui-mini";
222+
}
223+
224+
this
225+
._toggleClasses( this._content, "_contentTheme", opts.contentTheme ? ( "ui-body-" + opts.contentTheme ) : "" )
226+
._toggleClasses( $el, "_elClasses", classes )
227+
._toggleClasses( this._anchor, "_anchorClasses", anchorClasses );
228+
229+
return this._super( options );
174230
}
175231
});
176232

233+
// Defaults to be used by all instances of collapsible if per-instance values
234+
// are unset or if nothing is specified by way of inheritance from an accordion.
235+
$.mobile.collapsible.defaults = {
236+
expandCueText: " click to expand contents",
237+
collapseCueText: " click to collapse contents",
238+
collapsedIcon: "plus",
239+
expandedIcon: "minus",
240+
iconpos: "left",
241+
inset: true,
242+
corners: true,
243+
mini: false
244+
};
245+
177246
$.mobile.collapsible.initSelector = ":jqmData(role='collapsible')";
178247

179248
//auto self-init widgets

0 commit comments

Comments
 (0)