Improving jquery.makeCollapsible:
[lhc/web/wiklou.git] / resources / jquery / jquery.makeCollapsible.js
1 /**
2 * jQuery makeCollapsible
3 *
4 * This will enable collapsible-functionality on all passed elements.
5 * Will prevent binding twice to the same element.
6 * Initial state is expanded by default, this can be overriden by adding class
7 * "kr-collapsed" to the "kr-collapsible" element.
8 * Elements made collapsible have class "kr-made-collapsible".
9 * Except for tables and lists, the inner content is wrapped in "kr-collapsible-content".
10 *
11 * @author Krinkle <krinklemail@gmail.com>
12 *
13 * @TODO: Remove old "kr-" prefix
14 *
15 * Dual license:
16 * @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
17 * @license GPL2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
18 */
19
20 $.fn.makeCollapsible = function() {
21
22 return this.each(function() {
23
24 var $that = $(this).addClass( 'kr-collapsible' ), // in case $( '#myAJAXelement' ).makeCollapsible() was called
25 that = this,
26 collapsetext = $(this).attr( 'data-collapsetext' ),
27 expandtext = $(this).attr( 'data-expandtext' ),
28 toggleFunction = function( that ) {
29 var $that = $(that),
30 $collapsible = $that.closest( '.kr-collapsible.kr-made-collapsible' ).toggleClass( 'kr-collapsed' );
31
32 // It's expanded right now
33 if ( $that.hasClass( 'kr-collapsible-toggle-expanded' ) ) {
34 // Change link to "Show"
35 $that.removeClass( 'kr-collapsible-toggle-expanded' ).addClass( 'kr-collapsible-toggle-collapsed' );
36 if ( $that.find( '> a' ).size() ) {
37 $that.find( '> a' ).text( expandtext );
38 } else {
39 $that.text( expandtext );
40 }
41 // Hide the collapsible element
42 if ( $collapsible.is( 'table' ) ) {
43 // Hide all direct childing table rows of this table, except the row containing the link
44 // Slide doens't work, but fade works fine as of jQuery 1.1.3
45 // http://stackoverflow.com/questions/467336/jquery-how-to-use-slidedown-or-collapsed-function-on-a-table-row#920480
46 // Stop to prevent animations from stacking up
47 $collapsible.find( '> tbody > tr' ).not( $that.parent().parent() ).stop( true, true ).fadeOut();
48
49 } else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
50 $collapsible.find( '> li' ).not( $that.parent() ).stop( true, true ).slideUp();
51
52 } else { // <div>, <p> etc.
53 $collapsible.find( '> .kr-collapsible-content' ).slideUp();
54 }
55
56 // It's collapsed right now
57 } else {
58 // Change link to "Hide"
59 $that.removeClass( 'kr-collapsible-toggle-collapsed' ).addClass( 'kr-collapsible-toggle-expanded' );
60 if ( $that.find( '> a' ).size() ) {
61 $that.find( '> a' ).text( collapsetext );
62 } else {
63 $that.text( collapsetext );
64 }
65 // Show the collapsible element
66 if ( $collapsible.is( 'table' ) ) {
67 $collapsible.find( '> tbody > tr' ).not( $that.parent().parent() ).stop( true, true ).fadeIn();
68
69 } else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
70 $collapsible.find( '> li' ).not( $that.parent() ).stop( true, true ).slideDown();
71
72 } else { // <div>, <p> etc.
73 $collapsible.find( '> .kr-collapsible-content' ).slideDown();
74 }
75 }
76 return;
77 };
78
79 // Use custom text or default ?
80 if( !collapsetext || collapsetext == '' ){
81 collapsetext = mw.msg( 'collapsible-collapse' );
82 }
83 if ( !expandtext || expandtext == '' ){
84 expandtext = mw.msg( 'collapsible-expand' );
85 }
86
87 // Create toggle link with a space around the brackets (&nbsp;[text]&nbsp;)
88 var $toggleLink = $( '<a href="#">' ).text( collapsetext ).wrap( '<span class="kr-collapsible-toggle kr-collapsible-toggle-expanded">' ).parent().prepend( '&nbsp;[' ).append( ']&nbsp;' ).click( function(e){
89 e.preventDefault();
90 toggleFunction( this );
91 } );
92
93 // Skip if it has been enabled already.
94 if ( $that.hasClass( 'kr-made-collapsible' ) ) {
95 return;
96 } else {
97 $that.addClass( 'kr-made-collapsible' );
98 }
99
100 // Elements are treated differently
101 if ( $that.is( 'table' ) ) {
102 // The toggle-link will be in the last cell (td or th) of the first row
103 var $lastCell = $( 'tr:first th, tr:first td', that ).eq(-1),
104 $toggle = $lastCell.find( '> .kr-collapsible-toggle' );
105
106 if ( !$toggle.size() ) {
107 $lastCell.prepend( $toggleLink );
108 } else {
109 $toggleLink = $toggle.unbind( 'click' ).click( function( e ){
110 e.preventDefault();
111 toggleFunction( this );
112 } );
113 }
114
115 } else if ( $that.is( 'ul' ) || $that.is( 'ol' ) ) {
116 // The toggle-link will be in the first list-item
117 var $firstItem = $( 'li:first', $that),
118 $toggle = $firstItem.find( '> .kr-collapsible-toggle' );
119
120 if ( !$toggle.size() ) {
121 // Make sure the numeral order doesn't get messed up, reset to 1 unless value-attribute is already used
122 if ( $firstItem.attr( 'value' ) == '' ) {
123 $firstItem.attr( 'value', '1' );
124 }
125 $that.prepend( $toggleLink.wrap( '<li class="kr-collapsibile-toggle-li">' ).parent() );
126 } else {
127 $toggleLink = $toggle.unbind( 'click' ).click( function( e ){
128 e.preventDefault();
129 toggleFunction( this );
130 } );
131 }
132
133 } else { // <div>, <p> etc.
134 // Is there an content-wrapper already made ?
135 // If a direct child with the class does not exists, create the wrap.
136 if ( !$that.find( '> .kr-collapsible-content' ).size() ) {
137 $that.wrapInner( '<div class="kr-collapsible-content">' );
138 }
139
140 // The toggle-link will be the first child of the element
141 var $toggle = $that.find( '> .kr-collapsible-toggle' );
142
143 if ( !$toggle.size() ) {
144 $that.prepend( $toggleLink );
145 } else {
146 $toggleLink = $toggle.unbind( 'click' ).click( function( e ){
147 e.preventDefault();
148 toggleFunction( this );
149 } );
150 }
151
152 }
153 console.log( $toggleLink.get(0) );
154 // Initial state
155 if ( $that.hasClass( 'kr-collapsed' ) ) {
156 $toggleLink.click();
157 }
158 } );
159 };
160 $( function(){
161 $( '.kr-collapsible' ).makeCollapsible();
162 } );