corrade-http-templates – Blame information for rev 42

Subversion Repositories:
Rev:
Rev Author Line No. Line
42 office 1 /*!
2 * jQuery UI Accordion 1.12.1
3 * http://jqueryui.com
4 *
5 * Copyright jQuery Foundation and other contributors
6 * Released under the MIT license.
7 * http://jquery.org/license
8 */
9  
10 //>>label: Accordion
11 //>>group: Widgets
12 // jscs:disable maximumLineLength
13 //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
14 // jscs:enable maximumLineLength
15 //>>docs: http://api.jqueryui.com/accordion/
16 //>>demos: http://jqueryui.com/accordion/
17 //>>css.structure: ../../themes/base/core.css
18 //>>css.structure: ../../themes/base/accordion.css
19 //>>css.theme: ../../themes/base/theme.css
20  
21 ( function( factory ) {
22 if ( typeof define === "function" && define.amd ) {
23  
24 // AMD. Register as an anonymous module.
25 define( [
26 "jquery",
27 "../version",
28 "../keycode",
29 "../unique-id",
30 "../widget"
31 ], factory );
32 } else {
33  
34 // Browser globals
35 factory( jQuery );
36 }
37 }( function( $ ) {
38  
39 return $.widget( "ui.accordion", {
40 version: "1.12.1",
41 options: {
42 active: 0,
43 animate: {},
44 classes: {
45 "ui-accordion-header": "ui-corner-top",
46 "ui-accordion-header-collapsed": "ui-corner-all",
47 "ui-accordion-content": "ui-corner-bottom"
48 },
49 collapsible: false,
50 event: "click",
51 header: "> li > :first-child, > :not(li):even",
52 heightStyle: "auto",
53 icons: {
54 activeHeader: "ui-icon-triangle-1-s",
55 header: "ui-icon-triangle-1-e"
56 },
57  
58 // Callbacks
59 activate: null,
60 beforeActivate: null
61 },
62  
63 hideProps: {
64 borderTopWidth: "hide",
65 borderBottomWidth: "hide",
66 paddingTop: "hide",
67 paddingBottom: "hide",
68 height: "hide"
69 },
70  
71 showProps: {
72 borderTopWidth: "show",
73 borderBottomWidth: "show",
74 paddingTop: "show",
75 paddingBottom: "show",
76 height: "show"
77 },
78  
79 _create: function() {
80 var options = this.options;
81  
82 this.prevShow = this.prevHide = $();
83 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
84 this.element.attr( "role", "tablist" );
85  
86 // Don't allow collapsible: false and active: false / null
87 if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
88 options.active = 0;
89 }
90  
91 this._processPanels();
92  
93 // handle negative values
94 if ( options.active < 0 ) {
95 options.active += this.headers.length;
96 }
97 this._refresh();
98 },
99  
100 _getCreateEventData: function() {
101 return {
102 header: this.active,
103 panel: !this.active.length ? $() : this.active.next()
104 };
105 },
106  
107 _createIcons: function() {
108 var icon, children,
109 icons = this.options.icons;
110  
111 if ( icons ) {
112 icon = $( "<span>" );
113 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
114 icon.prependTo( this.headers );
115 children = this.active.children( ".ui-accordion-header-icon" );
116 this._removeClass( children, icons.header )
117 ._addClass( children, null, icons.activeHeader )
118 ._addClass( this.headers, "ui-accordion-icons" );
119 }
120 },
121  
122 _destroyIcons: function() {
123 this._removeClass( this.headers, "ui-accordion-icons" );
124 this.headers.children( ".ui-accordion-header-icon" ).remove();
125 },
126  
127 _destroy: function() {
128 var contents;
129  
130 // Clean up main element
131 this.element.removeAttr( "role" );
132  
133 // Clean up headers
134 this.headers
135 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
136 .removeUniqueId();
137  
138 this._destroyIcons();
139  
140 // Clean up content panels
141 contents = this.headers.next()
142 .css( "display", "" )
143 .removeAttr( "role aria-hidden aria-labelledby" )
144 .removeUniqueId();
145  
146 if ( this.options.heightStyle !== "content" ) {
147 contents.css( "height", "" );
148 }
149 },
150  
151 _setOption: function( key, value ) {
152 if ( key === "active" ) {
153  
154 // _activate() will handle invalid values and update this.options
155 this._activate( value );
156 return;
157 }
158  
159 if ( key === "event" ) {
160 if ( this.options.event ) {
161 this._off( this.headers, this.options.event );
162 }
163 this._setupEvents( value );
164 }
165  
166 this._super( key, value );
167  
168 // Setting collapsible: false while collapsed; open first panel
169 if ( key === "collapsible" && !value && this.options.active === false ) {
170 this._activate( 0 );
171 }
172  
173 if ( key === "icons" ) {
174 this._destroyIcons();
175 if ( value ) {
176 this._createIcons();
177 }
178 }
179 },
180  
181 _setOptionDisabled: function( value ) {
182 this._super( value );
183  
184 this.element.attr( "aria-disabled", value );
185  
186 // Support: IE8 Only
187 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
188 // so we need to add the disabled class to the headers and panels
189 this._toggleClass( null, "ui-state-disabled", !!value );
190 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
191 !!value );
192 },
193  
194 _keydown: function( event ) {
195 if ( event.altKey || event.ctrlKey ) {
196 return;
197 }
198  
199 var keyCode = $.ui.keyCode,
200 length = this.headers.length,
201 currentIndex = this.headers.index( event.target ),
202 toFocus = false;
203  
204 switch ( event.keyCode ) {
205 case keyCode.RIGHT:
206 case keyCode.DOWN:
207 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
208 break;
209 case keyCode.LEFT:
210 case keyCode.UP:
211 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
212 break;
213 case keyCode.SPACE:
214 case keyCode.ENTER:
215 this._eventHandler( event );
216 break;
217 case keyCode.HOME:
218 toFocus = this.headers[ 0 ];
219 break;
220 case keyCode.END:
221 toFocus = this.headers[ length - 1 ];
222 break;
223 }
224  
225 if ( toFocus ) {
226 $( event.target ).attr( "tabIndex", -1 );
227 $( toFocus ).attr( "tabIndex", 0 );
228 $( toFocus ).trigger( "focus" );
229 event.preventDefault();
230 }
231 },
232  
233 _panelKeyDown: function( event ) {
234 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
235 $( event.currentTarget ).prev().trigger( "focus" );
236 }
237 },
238  
239 refresh: function() {
240 var options = this.options;
241 this._processPanels();
242  
243 // Was collapsed or no panel
244 if ( ( options.active === false && options.collapsible === true ) ||
245 !this.headers.length ) {
246 options.active = false;
247 this.active = $();
248  
249 // active false only when collapsible is true
250 } else if ( options.active === false ) {
251 this._activate( 0 );
252  
253 // was active, but active panel is gone
254 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
255  
256 // all remaining panel are disabled
257 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
258 options.active = false;
259 this.active = $();
260  
261 // activate previous panel
262 } else {
263 this._activate( Math.max( 0, options.active - 1 ) );
264 }
265  
266 // was active, active panel still exists
267 } else {
268  
269 // make sure active index is correct
270 options.active = this.headers.index( this.active );
271 }
272  
273 this._destroyIcons();
274  
275 this._refresh();
276 },
277  
278 _processPanels: function() {
279 var prevHeaders = this.headers,
280 prevPanels = this.panels;
281  
282 this.headers = this.element.find( this.options.header );
283 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
284 "ui-state-default" );
285  
286 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
287 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
288  
289 // Avoid memory leaks (#10056)
290 if ( prevPanels ) {
291 this._off( prevHeaders.not( this.headers ) );
292 this._off( prevPanels.not( this.panels ) );
293 }
294 },
295  
296 _refresh: function() {
297 var maxHeight,
298 options = this.options,
299 heightStyle = options.heightStyle,
300 parent = this.element.parent();
301  
302 this.active = this._findActive( options.active );
303 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
304 ._removeClass( this.active, "ui-accordion-header-collapsed" );
305 this._addClass( this.active.next(), "ui-accordion-content-active" );
306 this.active.next().show();
307  
308 this.headers
309 .attr( "role", "tab" )
310 .each( function() {
311 var header = $( this ),
312 headerId = header.uniqueId().attr( "id" ),
313 panel = header.next(),
314 panelId = panel.uniqueId().attr( "id" );
315 header.attr( "aria-controls", panelId );
316 panel.attr( "aria-labelledby", headerId );
317 } )
318 .next()
319 .attr( "role", "tabpanel" );
320  
321 this.headers
322 .not( this.active )
323 .attr( {
324 "aria-selected": "false",
325 "aria-expanded": "false",
326 tabIndex: -1
327 } )
328 .next()
329 .attr( {
330 "aria-hidden": "true"
331 } )
332 .hide();
333  
334 // Make sure at least one header is in the tab order
335 if ( !this.active.length ) {
336 this.headers.eq( 0 ).attr( "tabIndex", 0 );
337 } else {
338 this.active.attr( {
339 "aria-selected": "true",
340 "aria-expanded": "true",
341 tabIndex: 0
342 } )
343 .next()
344 .attr( {
345 "aria-hidden": "false"
346 } );
347 }
348  
349 this._createIcons();
350  
351 this._setupEvents( options.event );
352  
353 if ( heightStyle === "fill" ) {
354 maxHeight = parent.height();
355 this.element.siblings( ":visible" ).each( function() {
356 var elem = $( this ),
357 position = elem.css( "position" );
358  
359 if ( position === "absolute" || position === "fixed" ) {
360 return;
361 }
362 maxHeight -= elem.outerHeight( true );
363 } );
364  
365 this.headers.each( function() {
366 maxHeight -= $( this ).outerHeight( true );
367 } );
368  
369 this.headers.next()
370 .each( function() {
371 $( this ).height( Math.max( 0, maxHeight -
372 $( this ).innerHeight() + $( this ).height() ) );
373 } )
374 .css( "overflow", "auto" );
375 } else if ( heightStyle === "auto" ) {
376 maxHeight = 0;
377 this.headers.next()
378 .each( function() {
379 var isVisible = $( this ).is( ":visible" );
380 if ( !isVisible ) {
381 $( this ).show();
382 }
383 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
384 if ( !isVisible ) {
385 $( this ).hide();
386 }
387 } )
388 .height( maxHeight );
389 }
390 },
391  
392 _activate: function( index ) {
393 var active = this._findActive( index )[ 0 ];
394  
395 // Trying to activate the already active panel
396 if ( active === this.active[ 0 ] ) {
397 return;
398 }
399  
400 // Trying to collapse, simulate a click on the currently active header
401 active = active || this.active[ 0 ];
402  
403 this._eventHandler( {
404 target: active,
405 currentTarget: active,
406 preventDefault: $.noop
407 } );
408 },
409  
410 _findActive: function( selector ) {
411 return typeof selector === "number" ? this.headers.eq( selector ) : $();
412 },
413  
414 _setupEvents: function( event ) {
415 var events = {
416 keydown: "_keydown"
417 };
418 if ( event ) {
419 $.each( event.split( " " ), function( index, eventName ) {
420 events[ eventName ] = "_eventHandler";
421 } );
422 }
423  
424 this._off( this.headers.add( this.headers.next() ) );
425 this._on( this.headers, events );
426 this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
427 this._hoverable( this.headers );
428 this._focusable( this.headers );
429 },
430  
431 _eventHandler: function( event ) {
432 var activeChildren, clickedChildren,
433 options = this.options,
434 active = this.active,
435 clicked = $( event.currentTarget ),
436 clickedIsActive = clicked[ 0 ] === active[ 0 ],
437 collapsing = clickedIsActive && options.collapsible,
438 toShow = collapsing ? $() : clicked.next(),
439 toHide = active.next(),
440 eventData = {
441 oldHeader: active,
442 oldPanel: toHide,
443 newHeader: collapsing ? $() : clicked,
444 newPanel: toShow
445 };
446  
447 event.preventDefault();
448  
449 if (
450  
451 // click on active header, but not collapsible
452 ( clickedIsActive && !options.collapsible ) ||
453  
454 // allow canceling activation
455 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
456 return;
457 }
458  
459 options.active = collapsing ? false : this.headers.index( clicked );
460  
461 // When the call to ._toggle() comes after the class changes
462 // it causes a very odd bug in IE 8 (see #6720)
463 this.active = clickedIsActive ? $() : clicked;
464 this._toggle( eventData );
465  
466 // Switch classes
467 // corner classes on the previously active header stay after the animation
468 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
469 if ( options.icons ) {
470 activeChildren = active.children( ".ui-accordion-header-icon" );
471 this._removeClass( activeChildren, null, options.icons.activeHeader )
472 ._addClass( activeChildren, null, options.icons.header );
473 }
474  
475 if ( !clickedIsActive ) {
476 this._removeClass( clicked, "ui-accordion-header-collapsed" )
477 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
478 if ( options.icons ) {
479 clickedChildren = clicked.children( ".ui-accordion-header-icon" );
480 this._removeClass( clickedChildren, null, options.icons.header )
481 ._addClass( clickedChildren, null, options.icons.activeHeader );
482 }
483  
484 this._addClass( clicked.next(), "ui-accordion-content-active" );
485 }
486 },
487  
488 _toggle: function( data ) {
489 var toShow = data.newPanel,
490 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
491  
492 // Handle activating a panel during the animation for another activation
493 this.prevShow.add( this.prevHide ).stop( true, true );
494 this.prevShow = toShow;
495 this.prevHide = toHide;
496  
497 if ( this.options.animate ) {
498 this._animate( toShow, toHide, data );
499 } else {
500 toHide.hide();
501 toShow.show();
502 this._toggleComplete( data );
503 }
504  
505 toHide.attr( {
506 "aria-hidden": "true"
507 } );
508 toHide.prev().attr( {
509 "aria-selected": "false",
510 "aria-expanded": "false"
511 } );
512  
513 // if we're switching panels, remove the old header from the tab order
514 // if we're opening from collapsed state, remove the previous header from the tab order
515 // if we're collapsing, then keep the collapsing header in the tab order
516 if ( toShow.length && toHide.length ) {
517 toHide.prev().attr( {
518 "tabIndex": -1,
519 "aria-expanded": "false"
520 } );
521 } else if ( toShow.length ) {
522 this.headers.filter( function() {
523 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
524 } )
525 .attr( "tabIndex", -1 );
526 }
527  
528 toShow
529 .attr( "aria-hidden", "false" )
530 .prev()
531 .attr( {
532 "aria-selected": "true",
533 "aria-expanded": "true",
534 tabIndex: 0
535 } );
536 },
537  
538 _animate: function( toShow, toHide, data ) {
539 var total, easing, duration,
540 that = this,
541 adjust = 0,
542 boxSizing = toShow.css( "box-sizing" ),
543 down = toShow.length &&
544 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
545 animate = this.options.animate || {},
546 options = down && animate.down || animate,
547 complete = function() {
548 that._toggleComplete( data );
549 };
550  
551 if ( typeof options === "number" ) {
552 duration = options;
553 }
554 if ( typeof options === "string" ) {
555 easing = options;
556 }
557  
558 // fall back from options to animation in case of partial down settings
559 easing = easing || options.easing || animate.easing;
560 duration = duration || options.duration || animate.duration;
561  
562 if ( !toHide.length ) {
563 return toShow.animate( this.showProps, duration, easing, complete );
564 }
565 if ( !toShow.length ) {
566 return toHide.animate( this.hideProps, duration, easing, complete );
567 }
568  
569 total = toShow.show().outerHeight();
570 toHide.animate( this.hideProps, {
571 duration: duration,
572 easing: easing,
573 step: function( now, fx ) {
574 fx.now = Math.round( now );
575 }
576 } );
577 toShow
578 .hide()
579 .animate( this.showProps, {
580 duration: duration,
581 easing: easing,
582 complete: complete,
583 step: function( now, fx ) {
584 fx.now = Math.round( now );
585 if ( fx.prop !== "height" ) {
586 if ( boxSizing === "content-box" ) {
587 adjust += fx.now;
588 }
589 } else if ( that.options.heightStyle !== "content" ) {
590 fx.now = Math.round( total - toHide.outerHeight() - adjust );
591 adjust = 0;
592 }
593 }
594 } );
595 },
596  
597 _toggleComplete: function( data ) {
598 var toHide = data.oldPanel,
599 prev = toHide.prev();
600  
601 this._removeClass( toHide, "ui-accordion-content-active" );
602 this._removeClass( prev, "ui-accordion-header-active" )
603 ._addClass( prev, "ui-accordion-header-collapsed" );
604  
605 // Work around for rendering bug in IE (#5421)
606 if ( toHide.length ) {
607 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
608 }
609 this._trigger( "activate", null, data );
610 }
611 } );
612  
613 } ) );