@@ -2,7 +2,7 @@ var $ = jQuery;
22/*!
33 *
44 * Bootstrap remote data tabs plugin
5- * Version 1.0 .1
5+ * Version 1.1 .1
66 *
77 * Author: Stephen Hoogendijk (TheCodeAssassin)
88 *
@@ -15,12 +15,25 @@ var hasLoadingMask = (jQuery().mask ? true : false),
1515 bootstrapVersion2 = ( jQuery ( ) . typeahead ? true : false ) ;
1616
1717// hook the event based on the version of bootstrap
18- var showEvent = ( bootstrapVersion2 ? 'show' : 'show.bs.tab' ) ;
18+ var tabShowEvent = ( bootstrapVersion2 ? 'show' : 'show.bs.tab' ) ;
19+ var accordionShowEvent = ( bootstrapVersion2 ? 'show' : 'show.bs.collapse' ) ;
1920
2021$ ( function ( ) {
22+ // try to navigate to the tab/accordion last given in the URL
2123 var hash = document . location . hash ;
2224 if ( hash ) {
23- $ ( '.nav-tabs a[href*=' + hash + ']' ) . tab ( showEvent ) ;
25+ var hasTab = $ ( '[data-toggle=tab][href=' + hash + ']' ) ;
26+ if ( hasTab ) {
27+ hasTab . tab ( 'show' ) ;
28+ }
29+
30+ var hasAccordion = $ ( '[data-toggle=collapse][href=' + hash + ']' ) ;
31+ if ( hasAccordion ) {
32+ // for some reason we cannot execute the 'show' event for an accordion properly, so here's a workaround
33+ if ( hasAccordion [ 0 ] != $ ( '[data-toggle=collapse]:first' ) [ 0 ] ) {
34+ hasAccordion . click ( ) ;
35+ }
36+ }
2437 }
2538} ) ;
2639var RemoteTabs = function ( ) {
@@ -33,85 +46,128 @@ var RemoteTabs = function() {
3346 * @param tabEvent
3447 * @param hasLoadingMask
3548 */
36- load : function ( tabEvent , hasLoadingMask ) {
49+ load : function ( hasLoadingMask ) {
3750
3851 var me = this ;
3952
4053 me . hasLoadingMask = ! ! hasLoadingMask ;
4154
4255 // enable all remote data tabs
43- $ ( '[data-toggle=tab]' ) . each ( function ( k , tab ) {
44- var tabObj = $ ( tab ) ,
45- tabDiv ,
46- tabData ,
47- tabCallback ,
56+ $ ( '[data-toggle=tab], [data-toggle=collapse] ' ) . each ( function ( k , obj ) {
57+ var bsObj = $ ( obj ) ,
58+ bsDiv ,
59+ bsData ,
60+ bsCallback ,
4861 url ,
4962 simulateDelay ,
50- alwaysRefresh ;
63+ alwaysRefresh ,
64+ hasOpenPanel = false ,
65+ originalObj ;
5166
5267 // check if the tab has a data-url property
53- if ( tabObj . is ( '[data-tab-url]' ) ) {
54- url = tabObj . attr ( 'data-tab-url' ) ;
55- tabDiv = $ ( '#' + tabObj . attr ( 'href' ) . split ( '#' ) [ 1 ] ) ;
56- tabData = tabObj . attr ( 'data-tab-json' ) || [ ] ;
57- tabCallback = tabObj . attr ( 'data-tab-callback' ) || null ;
58- simulateDelay = tabObj . attr ( 'data-tab-delay' ) || null ;
59- alwaysRefresh = ( tabObj . is ( '[data-tab-always-refresh]' )
60- && tabObj . attr ( 'data-tab-always-refresh' ) == 'true' ) || null ;
61-
62- if ( tabData . length > 0 ) {
68+ if ( bsObj . is ( '[data-tab-url]' ) ) {
69+ url = bsObj . attr ( 'data-tab-url' ) ;
70+ bsDiv = $ ( '#' + bsObj . attr ( 'href' ) . split ( '#' ) [ 1 ] ) ;
71+ bsData = bsObj . attr ( 'data-tab-json' ) || [ ] ;
72+ bsCallback = bsObj . attr ( 'data-tab-callback' ) || null ;
73+ simulateDelay = bsObj . attr ( 'data-tab-delay' ) || null ;
74+ alwaysRefresh = ( bsObj . is ( '[data-tab-always-refresh]' )
75+ && bsObj . attr ( 'data-tab-always-refresh' ) == 'true' ) || null ,
76+ originalObj = bsObj ,
77+ showEvent = ( bsObj . attr ( 'data-toggle' ) == 'tab' ? tabShowEvent : accordionShowEvent ) ;
78+
79+ if ( bsData . length > 0 ) {
6380 try
6481 {
65- tabData = $ . parseJSON ( tabData ) ;
82+ bsData = $ . parseJSON ( bsData ) ;
6683 } catch ( exc ) {
6784 console . log ( 'Invalid json passed to data-tab-json' ) ;
6885 console . log ( exc ) ;
6986 }
7087
7188 }
72-
73- tabObj . on ( tabEvent , function ( e ) {
74-
75- // change the hash of the location
76- window . location . hash = e . target . hash ;
77-
78- if ( ( ! tabObj . hasClass ( "loaded" ) || alwaysRefresh ) &&
79- ! tabObj . hasClass ( 'loading' ) ) {
80-
81- if ( me . hasLoadingMask ) {
82- tabDiv . mask ( 'Loading...' ) ;
83- }
84- tabObj . addClass ( 'loading' ) ;
85-
86- // delay the json call if it has been given a value
87- if ( simulateDelay ) {
88- clearTimeout ( window . timer ) ;
89- window . timer = setTimeout ( function ( ) {
90- me . _executeRemoteCall ( url , tabData , tabCallback , tabObj , tabDiv ) ;
91- } , simulateDelay ) ;
92- } else {
93- me . _executeRemoteCall ( url , tabData , tabCallback , tabObj , tabDiv ) ;
94- }
95-
96-
89+
90+ if ( showEvent == accordionShowEvent ) {
91+ hasOpenPanel = bsDiv . hasClass ( 'in' ) ;
92+ // when an accordion is triggered, make the div the triggered object instead of the link
93+ if ( bootstrapVersion2 ) {
94+ bsObj = bsObj . parent ( ) ;
95+ } else {
96+ bsObj = bsObj . parents ( '.panel' ) ;
9797 }
98-
98+
99+ // If there is a panel already opened, make sure the data url is fetched
100+ if ( hasOpenPanel ) {
101+ me . _triggerChange ( null , url , bsData , bsCallback , bsObj , bsDiv , simulateDelay , alwaysRefresh , originalObj ) ;
102+ }
103+ }
104+
105+ bsObj . on ( showEvent , function ( e ) {
106+ me . _triggerChange ( e , url , bsData , bsCallback , bsObj , bsDiv , simulateDelay , alwaysRefresh , originalObj ) ;
99107 } ) ;
100108
101109 }
102110 } ) ;
103111 } ,
104112
113+ /**
114+ * Trigger the change
115+ *
116+ * @param e
117+ * @param url
118+ * @param bsData
119+ * @param bsCallback
120+ * @param bsObj
121+ * @param bsDiv
122+ * @param simulateDelay
123+ * @param alwaysRefresh
124+ * @param originalObj
125+ */
126+ _triggerChange : function ( e , url , bsData , bsCallback , bsObj , bsDiv , simulateDelay , alwaysRefresh , originalObj ) {
127+ var me = this ;
128+
129+ // change the hash of the location
130+ if ( e ) {
131+ if ( typeof e . target . hash != 'undefined' ) {
132+ window . location . hash = e . target . hash ;
133+ } else {
134+ window . location . hash = originalObj . prop ( 'hash' ) ;
135+ }
136+ }
137+
138+ if ( ( ! bsObj . hasClass ( "loaded" ) || alwaysRefresh ) &&
139+ ! bsObj . hasClass ( 'loading' ) ) {
140+
141+ if ( me . hasLoadingMask ) {
142+ bsDiv . mask ( 'Loading...' ) ;
143+ }
144+ bsObj . addClass ( 'loading' ) ;
145+
146+ // delay the json call if it has been given a value
147+ if ( simulateDelay ) {
148+ clearTimeout ( window . timer ) ;
149+ window . timer = setTimeout ( function ( ) {
150+ me . _executeRemoteCall ( url , bsData , bsCallback , bsObj , bsDiv ) ;
151+ } , simulateDelay ) ;
152+ } else {
153+ me . _executeRemoteCall ( url , bsData , bsCallback , bsObj , bsDiv ) ;
154+ }
155+
156+
157+ }
158+ } ,
159+
160+
105161 /**
106162 * Execute the remote call
107163 * @param url
108164 * @param customData
109165 * @param callbackFn
110166 * @param trigger
111- * @param tabContainer
167+ * @param dataContainer
112168 * @private
113169 */
114- _executeRemoteCall : function ( url , customData , callbackFn , trigger , tabContainer ) {
170+ _executeRemoteCall : function ( url , customData , callbackFn , trigger , dataContainer ) {
115171 var me = this ;
116172
117173
@@ -121,29 +177,30 @@ var RemoteTabs = function() {
121177 success : function ( data ) {
122178 trigger . removeClass ( 'loading' ) ;
123179 if ( me . hasLoadingMask ) {
124- tabContainer . unmask ( ) ;
180+ dataContainer . unmask ( ) ;
125181 }
126182 if ( data ) {
127183 if ( typeof window [ callbackFn ] == 'function' ) {
128- window [ callbackFn ] . call ( null , data , trigger , tabContainer , customData ) ;
184+ window [ callbackFn ] . call ( null , data , trigger , dataContainer , customData ) ;
129185 }
130186 if ( ! trigger . hasClass ( "loaded" ) ) {
131187 trigger . addClass ( "loaded" ) ;
132188 }
133- tabContainer . html ( data ) ;
189+ dataContainer . html ( data ) ;
134190 }
135191 } ,
136- fail : function ( data ) {
192+ error : function ( data , status , error ) {
193+ dataContainer . html ( "An error occured while loading the data: " + error ) ;
137194 trigger . removeClass ( 'loading' ) ;
138195 if ( me . hasLoadingMask ) {
139- tabContainer . unmask ( ) ;
196+ dataContainer . unmask ( ) ;
140197 }
141198 }
142199 } ) ;
143200 }
144201 } ;
145202
146- obj . load ( showEvent , hasLoadingMask ) ;
203+ obj . load ( hasLoadingMask ) ;
147204
148205 return obj ;
149206} ;
0 commit comments