1 | /* |
---|
2 | * jQuery UI Tabs 1.8.17 |
---|
3 | * |
---|
4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) |
---|
5 | * Dual licensed under the MIT or GPL Version 2 licenses. |
---|
6 | * http://jquery.org/license |
---|
7 | * |
---|
8 | * http://docs.jquery.com/UI/Tabs |
---|
9 | * |
---|
10 | * Depends: |
---|
11 | * jquery.ui.core.js |
---|
12 | * jquery.ui.widget.js |
---|
13 | */ |
---|
14 | (function( $, undefined ) { |
---|
15 | |
---|
16 | var tabId = 0, |
---|
17 | listId = 0; |
---|
18 | |
---|
19 | function getNextTabId() { |
---|
20 | return ++tabId; |
---|
21 | } |
---|
22 | |
---|
23 | function getNextListId() { |
---|
24 | return ++listId; |
---|
25 | } |
---|
26 | |
---|
27 | $.widget( "ui.tabs", { |
---|
28 | options: { |
---|
29 | add: null, |
---|
30 | ajaxOptions: null, |
---|
31 | cache: false, |
---|
32 | cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true } |
---|
33 | collapsible: false, |
---|
34 | disable: null, |
---|
35 | disabled: [], |
---|
36 | enable: null, |
---|
37 | event: "click", |
---|
38 | fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 } |
---|
39 | idPrefix: "ui-tabs-", |
---|
40 | load: null, |
---|
41 | panelTemplate: "<div></div>", |
---|
42 | remove: null, |
---|
43 | select: null, |
---|
44 | show: null, |
---|
45 | spinner: "<em>Loading…</em>", |
---|
46 | tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>" |
---|
47 | }, |
---|
48 | |
---|
49 | _create: function() { |
---|
50 | this._tabify( true ); |
---|
51 | }, |
---|
52 | |
---|
53 | _setOption: function( key, value ) { |
---|
54 | if ( key == "selected" ) { |
---|
55 | if (this.options.collapsible && value == this.options.selected ) { |
---|
56 | return; |
---|
57 | } |
---|
58 | this.select( value ); |
---|
59 | } else { |
---|
60 | this.options[ key ] = value; |
---|
61 | this._tabify(); |
---|
62 | } |
---|
63 | }, |
---|
64 | |
---|
65 | _tabId: function( a ) { |
---|
66 | return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || |
---|
67 | this.options.idPrefix + getNextTabId(); |
---|
68 | }, |
---|
69 | |
---|
70 | _sanitizeSelector: function( hash ) { |
---|
71 | // we need this because an id may contain a ":" |
---|
72 | return hash.replace( /:/g, "\\:" ); |
---|
73 | }, |
---|
74 | |
---|
75 | _cookie: function() { |
---|
76 | var cookie = this.cookie || |
---|
77 | ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() ); |
---|
78 | return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) ); |
---|
79 | }, |
---|
80 | |
---|
81 | _ui: function( tab, panel ) { |
---|
82 | return { |
---|
83 | tab: tab, |
---|
84 | panel: panel, |
---|
85 | index: this.anchors.index( tab ) |
---|
86 | }; |
---|
87 | }, |
---|
88 | |
---|
89 | _cleanup: function() { |
---|
90 | // restore all former loading tabs labels |
---|
91 | this.lis.filter( ".ui-state-processing" ) |
---|
92 | .removeClass( "ui-state-processing" ) |
---|
93 | .find( "span:data(label.tabs)" ) |
---|
94 | .each(function() { |
---|
95 | var el = $( this ); |
---|
96 | el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" ); |
---|
97 | }); |
---|
98 | }, |
---|
99 | |
---|
100 | _tabify: function( init ) { |
---|
101 | var self = this, |
---|
102 | o = this.options, |
---|
103 | fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash |
---|
104 | |
---|
105 | this.list = this.element.find( "ol,ul" ).eq( 0 ); |
---|
106 | this.lis = $( " > li:has(a[href])", this.list ); |
---|
107 | this.anchors = this.lis.map(function() { |
---|
108 | return $( "a", this )[ 0 ]; |
---|
109 | }); |
---|
110 | this.panels = $( [] ); |
---|
111 | |
---|
112 | this.anchors.each(function( i, a ) { |
---|
113 | var href = $( a ).attr( "href" ); |
---|
114 | // For dynamically created HTML that contains a hash as href IE < 8 expands |
---|
115 | // such href to the full page url with hash and then misinterprets tab as ajax. |
---|
116 | // Same consideration applies for an added tab with a fragment identifier |
---|
117 | // since a[href=#fragment-identifier] does unexpectedly not match. |
---|
118 | // Thus normalize href attribute... |
---|
119 | var hrefBase = href.split( "#" )[ 0 ], |
---|
120 | baseEl; |
---|
121 | if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] || |
---|
122 | ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) { |
---|
123 | href = a.hash; |
---|
124 | a.href = href; |
---|
125 | } |
---|
126 | |
---|
127 | // inline tab |
---|
128 | if ( fragmentId.test( href ) ) { |
---|
129 | self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) ); |
---|
130 | // remote tab |
---|
131 | // prevent loading the page itself if href is just "#" |
---|
132 | } else if ( href && href !== "#" ) { |
---|
133 | // required for restore on destroy |
---|
134 | $.data( a, "href.tabs", href ); |
---|
135 | |
---|
136 | // TODO until #3808 is fixed strip fragment identifier from url |
---|
137 | // (IE fails to load from such url) |
---|
138 | $.data( a, "load.tabs", href.replace( /#.*$/, "" ) ); |
---|
139 | |
---|
140 | var id = self._tabId( a ); |
---|
141 | a.href = "#" + id; |
---|
142 | var $panel = self.element.find( "#" + id ); |
---|
143 | if ( !$panel.length ) { |
---|
144 | $panel = $( o.panelTemplate ) |
---|
145 | .attr( "id", id ) |
---|
146 | .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) |
---|
147 | .insertAfter( self.panels[ i - 1 ] || self.list ); |
---|
148 | $panel.data( "destroy.tabs", true ); |
---|
149 | } |
---|
150 | self.panels = self.panels.add( $panel ); |
---|
151 | // invalid tab href |
---|
152 | } else { |
---|
153 | o.disabled.push( i ); |
---|
154 | } |
---|
155 | }); |
---|
156 | |
---|
157 | // initialization from scratch |
---|
158 | if ( init ) { |
---|
159 | // attach necessary classes for styling |
---|
160 | this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ); |
---|
161 | this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); |
---|
162 | this.lis.addClass( "ui-state-default ui-corner-top" ); |
---|
163 | this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ); |
---|
164 | |
---|
165 | // Selected tab |
---|
166 | // use "selected" option or try to retrieve: |
---|
167 | // 1. from fragment identifier in url |
---|
168 | // 2. from cookie |
---|
169 | // 3. from selected class attribute on <li> |
---|
170 | if ( o.selected === undefined ) { |
---|
171 | if ( location.hash ) { |
---|
172 | this.anchors.each(function( i, a ) { |
---|
173 | if ( a.hash == location.hash ) { |
---|
174 | o.selected = i; |
---|
175 | return false; |
---|
176 | } |
---|
177 | }); |
---|
178 | } |
---|
179 | if ( typeof o.selected !== "number" && o.cookie ) { |
---|
180 | o.selected = parseInt( self._cookie(), 10 ); |
---|
181 | } |
---|
182 | if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) { |
---|
183 | o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); |
---|
184 | } |
---|
185 | o.selected = o.selected || ( this.lis.length ? 0 : -1 ); |
---|
186 | } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release |
---|
187 | o.selected = -1; |
---|
188 | } |
---|
189 | |
---|
190 | // sanity check - default to first tab... |
---|
191 | o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 ) |
---|
192 | ? o.selected |
---|
193 | : 0; |
---|
194 | |
---|
195 | // Take disabling tabs via class attribute from HTML |
---|
196 | // into account and update option properly. |
---|
197 | // A selected tab cannot become disabled. |
---|
198 | o.disabled = $.unique( o.disabled.concat( |
---|
199 | $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) { |
---|
200 | return self.lis.index( n ); |
---|
201 | }) |
---|
202 | ) ).sort(); |
---|
203 | |
---|
204 | if ( $.inArray( o.selected, o.disabled ) != -1 ) { |
---|
205 | o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 ); |
---|
206 | } |
---|
207 | |
---|
208 | // highlight selected tab |
---|
209 | this.panels.addClass( "ui-tabs-hide" ); |
---|
210 | this.lis.removeClass( "ui-tabs-selected ui-state-active" ); |
---|
211 | // check for length avoids error when initializing empty list |
---|
212 | if ( o.selected >= 0 && this.anchors.length ) { |
---|
213 | self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" ); |
---|
214 | this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" ); |
---|
215 | |
---|
216 | // seems to be expected behavior that the show callback is fired |
---|
217 | self.element.queue( "tabs", function() { |
---|
218 | self._trigger( "show", null, |
---|
219 | self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) ); |
---|
220 | }); |
---|
221 | |
---|
222 | this.load( o.selected ); |
---|
223 | } |
---|
224 | |
---|
225 | // clean up to avoid memory leaks in certain versions of IE 6 |
---|
226 | // TODO: namespace this event |
---|
227 | $( window ).bind( "unload", function() { |
---|
228 | self.lis.add( self.anchors ).unbind( ".tabs" ); |
---|
229 | self.lis = self.anchors = self.panels = null; |
---|
230 | }); |
---|
231 | // update selected after add/remove |
---|
232 | } else { |
---|
233 | o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) ); |
---|
234 | } |
---|
235 | |
---|
236 | // update collapsible |
---|
237 | // TODO: use .toggleClass() |
---|
238 | this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" ); |
---|
239 | |
---|
240 | // set or update cookie after init and add/remove respectively |
---|
241 | if ( o.cookie ) { |
---|
242 | this._cookie( o.selected, o.cookie ); |
---|
243 | } |
---|
244 | |
---|
245 | // disable tabs |
---|
246 | for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) { |
---|
247 | $( li )[ $.inArray( i, o.disabled ) != -1 && |
---|
248 | // TODO: use .toggleClass() |
---|
249 | !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" ); |
---|
250 | } |
---|
251 | |
---|
252 | // reset cache if switching from cached to not cached |
---|
253 | if ( o.cache === false ) { |
---|
254 | this.anchors.removeData( "cache.tabs" ); |
---|
255 | } |
---|
256 | |
---|
257 | // remove all handlers before, tabify may run on existing tabs after add or option change |
---|
258 | this.lis.add( this.anchors ).unbind( ".tabs" ); |
---|
259 | |
---|
260 | if ( o.event !== "mouseover" ) { |
---|
261 | var addState = function( state, el ) { |
---|
262 | if ( el.is( ":not(.ui-state-disabled)" ) ) { |
---|
263 | el.addClass( "ui-state-" + state ); |
---|
264 | } |
---|
265 | }; |
---|
266 | var removeState = function( state, el ) { |
---|
267 | el.removeClass( "ui-state-" + state ); |
---|
268 | }; |
---|
269 | this.lis.bind( "mouseover.tabs" , function() { |
---|
270 | addState( "hover", $( this ) ); |
---|
271 | }); |
---|
272 | this.lis.bind( "mouseout.tabs", function() { |
---|
273 | removeState( "hover", $( this ) ); |
---|
274 | }); |
---|
275 | this.anchors.bind( "focus.tabs", function() { |
---|
276 | addState( "focus", $( this ).closest( "li" ) ); |
---|
277 | }); |
---|
278 | this.anchors.bind( "blur.tabs", function() { |
---|
279 | removeState( "focus", $( this ).closest( "li" ) ); |
---|
280 | }); |
---|
281 | } |
---|
282 | |
---|
283 | // set up animations |
---|
284 | var hideFx, showFx; |
---|
285 | if ( o.fx ) { |
---|
286 | if ( $.isArray( o.fx ) ) { |
---|
287 | hideFx = o.fx[ 0 ]; |
---|
288 | showFx = o.fx[ 1 ]; |
---|
289 | } else { |
---|
290 | hideFx = showFx = o.fx; |
---|
291 | } |
---|
292 | } |
---|
293 | |
---|
294 | // Reset certain styles left over from animation |
---|
295 | // and prevent IE's ClearType bug... |
---|
296 | function resetStyle( $el, fx ) { |
---|
297 | $el.css( "display", "" ); |
---|
298 | if ( !$.support.opacity && fx.opacity ) { |
---|
299 | $el[ 0 ].style.removeAttribute( "filter" ); |
---|
300 | } |
---|
301 | } |
---|
302 | |
---|
303 | // Show a tab... |
---|
304 | var showTab = showFx |
---|
305 | ? function( clicked, $show ) { |
---|
306 | $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); |
---|
307 | $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way |
---|
308 | .animate( showFx, showFx.duration || "normal", function() { |
---|
309 | resetStyle( $show, showFx ); |
---|
310 | self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); |
---|
311 | }); |
---|
312 | } |
---|
313 | : function( clicked, $show ) { |
---|
314 | $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" ); |
---|
315 | $show.removeClass( "ui-tabs-hide" ); |
---|
316 | self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) ); |
---|
317 | }; |
---|
318 | |
---|
319 | // Hide a tab, $show is optional... |
---|
320 | var hideTab = hideFx |
---|
321 | ? function( clicked, $hide ) { |
---|
322 | $hide.animate( hideFx, hideFx.duration || "normal", function() { |
---|
323 | self.lis.removeClass( "ui-tabs-selected ui-state-active" ); |
---|
324 | $hide.addClass( "ui-tabs-hide" ); |
---|
325 | resetStyle( $hide, hideFx ); |
---|
326 | self.element.dequeue( "tabs" ); |
---|
327 | }); |
---|
328 | } |
---|
329 | : function( clicked, $hide, $show ) { |
---|
330 | self.lis.removeClass( "ui-tabs-selected ui-state-active" ); |
---|
331 | $hide.addClass( "ui-tabs-hide" ); |
---|
332 | self.element.dequeue( "tabs" ); |
---|
333 | }; |
---|
334 | |
---|
335 | // attach tab event handler, unbind to avoid duplicates from former tabifying... |
---|
336 | this.anchors.bind( o.event + ".tabs", function() { |
---|
337 | var el = this, |
---|
338 | $li = $(el).closest( "li" ), |
---|
339 | $hide = self.panels.filter( ":not(.ui-tabs-hide)" ), |
---|
340 | $show = self.element.find( self._sanitizeSelector( el.hash ) ); |
---|
341 | |
---|
342 | // If tab is already selected and not collapsible or tab disabled or |
---|
343 | // or is already loading or click callback returns false stop here. |
---|
344 | // Check if click handler returns false last so that it is not executed |
---|
345 | // for a disabled or loading tab! |
---|
346 | if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) || |
---|
347 | $li.hasClass( "ui-state-disabled" ) || |
---|
348 | $li.hasClass( "ui-state-processing" ) || |
---|
349 | self.panels.filter( ":animated" ).length || |
---|
350 | self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) { |
---|
351 | this.blur(); |
---|
352 | return false; |
---|
353 | } |
---|
354 | |
---|
355 | o.selected = self.anchors.index( this ); |
---|
356 | |
---|
357 | self.abort(); |
---|
358 | |
---|
359 | // if tab may be closed |
---|
360 | if ( o.collapsible ) { |
---|
361 | if ( $li.hasClass( "ui-tabs-selected" ) ) { |
---|
362 | o.selected = -1; |
---|
363 | |
---|
364 | if ( o.cookie ) { |
---|
365 | self._cookie( o.selected, o.cookie ); |
---|
366 | } |
---|
367 | |
---|
368 | self.element.queue( "tabs", function() { |
---|
369 | hideTab( el, $hide ); |
---|
370 | }).dequeue( "tabs" ); |
---|
371 | |
---|
372 | this.blur(); |
---|
373 | return false; |
---|
374 | } else if ( !$hide.length ) { |
---|
375 | if ( o.cookie ) { |
---|
376 | self._cookie( o.selected, o.cookie ); |
---|
377 | } |
---|
378 | |
---|
379 | self.element.queue( "tabs", function() { |
---|
380 | showTab( el, $show ); |
---|
381 | }); |
---|
382 | |
---|
383 | // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171 |
---|
384 | self.load( self.anchors.index( this ) ); |
---|
385 | |
---|
386 | this.blur(); |
---|
387 | return false; |
---|
388 | } |
---|
389 | } |
---|
390 | |
---|
391 | if ( o.cookie ) { |
---|
392 | self._cookie( o.selected, o.cookie ); |
---|
393 | } |
---|
394 | |
---|
395 | // show new tab |
---|
396 | if ( $show.length ) { |
---|
397 | if ( $hide.length ) { |
---|
398 | self.element.queue( "tabs", function() { |
---|
399 | hideTab( el, $hide ); |
---|
400 | }); |
---|
401 | } |
---|
402 | self.element.queue( "tabs", function() { |
---|
403 | showTab( el, $show ); |
---|
404 | }); |
---|
405 | |
---|
406 | self.load( self.anchors.index( this ) ); |
---|
407 | } else { |
---|
408 | throw "jQuery UI Tabs: Mismatching fragment identifier."; |
---|
409 | } |
---|
410 | |
---|
411 | // Prevent IE from keeping other link focussed when using the back button |
---|
412 | // and remove dotted border from clicked link. This is controlled via CSS |
---|
413 | // in modern browsers; blur() removes focus from address bar in Firefox |
---|
414 | // which can become a usability and annoying problem with tabs('rotate'). |
---|
415 | if ( $.browser.msie ) { |
---|
416 | this.blur(); |
---|
417 | } |
---|
418 | }); |
---|
419 | |
---|
420 | // disable click in any case |
---|
421 | this.anchors.bind( "click.tabs", function(){ |
---|
422 | return false; |
---|
423 | }); |
---|
424 | }, |
---|
425 | |
---|
426 | _getIndex: function( index ) { |
---|
427 | // meta-function to give users option to provide a href string instead of a numerical index. |
---|
428 | // also sanitizes numerical indexes to valid values. |
---|
429 | if ( typeof index == "string" ) { |
---|
430 | index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) ); |
---|
431 | } |
---|
432 | |
---|
433 | return index; |
---|
434 | }, |
---|
435 | |
---|
436 | destroy: function() { |
---|
437 | var o = this.options; |
---|
438 | |
---|
439 | this.abort(); |
---|
440 | |
---|
441 | this.element |
---|
442 | .unbind( ".tabs" ) |
---|
443 | .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ) |
---|
444 | .removeData( "tabs" ); |
---|
445 | |
---|
446 | this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ); |
---|
447 | |
---|
448 | this.anchors.each(function() { |
---|
449 | var href = $.data( this, "href.tabs" ); |
---|
450 | if ( href ) { |
---|
451 | this.href = href; |
---|
452 | } |
---|
453 | var $this = $( this ).unbind( ".tabs" ); |
---|
454 | $.each( [ "href", "load", "cache" ], function( i, prefix ) { |
---|
455 | $this.removeData( prefix + ".tabs" ); |
---|
456 | }); |
---|
457 | }); |
---|
458 | |
---|
459 | this.lis.unbind( ".tabs" ).add( this.panels ).each(function() { |
---|
460 | if ( $.data( this, "destroy.tabs" ) ) { |
---|
461 | $( this ).remove(); |
---|
462 | } else { |
---|
463 | $( this ).removeClass([ |
---|
464 | "ui-state-default", |
---|
465 | "ui-corner-top", |
---|
466 | "ui-tabs-selected", |
---|
467 | "ui-state-active", |
---|
468 | "ui-state-hover", |
---|
469 | "ui-state-focus", |
---|
470 | "ui-state-disabled", |
---|
471 | "ui-tabs-panel", |
---|
472 | "ui-widget-content", |
---|
473 | "ui-corner-bottom", |
---|
474 | "ui-tabs-hide" |
---|
475 | ].join( " " ) ); |
---|
476 | } |
---|
477 | }); |
---|
478 | |
---|
479 | if ( o.cookie ) { |
---|
480 | this._cookie( null, o.cookie ); |
---|
481 | } |
---|
482 | |
---|
483 | return this; |
---|
484 | }, |
---|
485 | |
---|
486 | add: function( url, label, index ) { |
---|
487 | if ( index === undefined ) { |
---|
488 | index = this.anchors.length; |
---|
489 | } |
---|
490 | |
---|
491 | var self = this, |
---|
492 | o = this.options, |
---|
493 | $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ), |
---|
494 | id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] ); |
---|
495 | |
---|
496 | $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true ); |
---|
497 | |
---|
498 | // try to find an existing element before creating a new one |
---|
499 | var $panel = self.element.find( "#" + id ); |
---|
500 | if ( !$panel.length ) { |
---|
501 | $panel = $( o.panelTemplate ) |
---|
502 | .attr( "id", id ) |
---|
503 | .data( "destroy.tabs", true ); |
---|
504 | } |
---|
505 | $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" ); |
---|
506 | |
---|
507 | if ( index >= this.lis.length ) { |
---|
508 | $li.appendTo( this.list ); |
---|
509 | $panel.appendTo( this.list[ 0 ].parentNode ); |
---|
510 | } else { |
---|
511 | $li.insertBefore( this.lis[ index ] ); |
---|
512 | $panel.insertBefore( this.panels[ index ] ); |
---|
513 | } |
---|
514 | |
---|
515 | o.disabled = $.map( o.disabled, function( n, i ) { |
---|
516 | return n >= index ? ++n : n; |
---|
517 | }); |
---|
518 | |
---|
519 | this._tabify(); |
---|
520 | |
---|
521 | if ( this.anchors.length == 1 ) { |
---|
522 | o.selected = 0; |
---|
523 | $li.addClass( "ui-tabs-selected ui-state-active" ); |
---|
524 | $panel.removeClass( "ui-tabs-hide" ); |
---|
525 | this.element.queue( "tabs", function() { |
---|
526 | self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) ); |
---|
527 | }); |
---|
528 | |
---|
529 | this.load( 0 ); |
---|
530 | } |
---|
531 | |
---|
532 | this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); |
---|
533 | return this; |
---|
534 | }, |
---|
535 | |
---|
536 | remove: function( index ) { |
---|
537 | index = this._getIndex( index ); |
---|
538 | var o = this.options, |
---|
539 | $li = this.lis.eq( index ).remove(), |
---|
540 | $panel = this.panels.eq( index ).remove(); |
---|
541 | |
---|
542 | // If selected tab was removed focus tab to the right or |
---|
543 | // in case the last tab was removed the tab to the left. |
---|
544 | if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) { |
---|
545 | this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) ); |
---|
546 | } |
---|
547 | |
---|
548 | o.disabled = $.map( |
---|
549 | $.grep( o.disabled, function(n, i) { |
---|
550 | return n != index; |
---|
551 | }), |
---|
552 | function( n, i ) { |
---|
553 | return n >= index ? --n : n; |
---|
554 | }); |
---|
555 | |
---|
556 | this._tabify(); |
---|
557 | |
---|
558 | this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) ); |
---|
559 | return this; |
---|
560 | }, |
---|
561 | |
---|
562 | enable: function( index ) { |
---|
563 | index = this._getIndex( index ); |
---|
564 | var o = this.options; |
---|
565 | if ( $.inArray( index, o.disabled ) == -1 ) { |
---|
566 | return; |
---|
567 | } |
---|
568 | |
---|
569 | this.lis.eq( index ).removeClass( "ui-state-disabled" ); |
---|
570 | o.disabled = $.grep( o.disabled, function( n, i ) { |
---|
571 | return n != index; |
---|
572 | }); |
---|
573 | |
---|
574 | this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); |
---|
575 | return this; |
---|
576 | }, |
---|
577 | |
---|
578 | disable: function( index ) { |
---|
579 | index = this._getIndex( index ); |
---|
580 | var self = this, o = this.options; |
---|
581 | // cannot disable already selected tab |
---|
582 | if ( index != o.selected ) { |
---|
583 | this.lis.eq( index ).addClass( "ui-state-disabled" ); |
---|
584 | |
---|
585 | o.disabled.push( index ); |
---|
586 | o.disabled.sort(); |
---|
587 | |
---|
588 | this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); |
---|
589 | } |
---|
590 | |
---|
591 | return this; |
---|
592 | }, |
---|
593 | |
---|
594 | select: function( index ) { |
---|
595 | index = this._getIndex( index ); |
---|
596 | if ( index == -1 ) { |
---|
597 | if ( this.options.collapsible && this.options.selected != -1 ) { |
---|
598 | index = this.options.selected; |
---|
599 | } else { |
---|
600 | return this; |
---|
601 | } |
---|
602 | } |
---|
603 | this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); |
---|
604 | return this; |
---|
605 | }, |
---|
606 | |
---|
607 | load: function( index ) { |
---|
608 | index = this._getIndex( index ); |
---|
609 | var self = this, |
---|
610 | o = this.options, |
---|
611 | a = this.anchors.eq( index )[ 0 ], |
---|
612 | url = $.data( a, "load.tabs" ); |
---|
613 | |
---|
614 | this.abort(); |
---|
615 | |
---|
616 | // not remote or from cache |
---|
617 | if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) { |
---|
618 | this.element.dequeue( "tabs" ); |
---|
619 | return; |
---|
620 | } |
---|
621 | |
---|
622 | // load remote from here on |
---|
623 | this.lis.eq( index ).addClass( "ui-state-processing" ); |
---|
624 | |
---|
625 | if ( o.spinner ) { |
---|
626 | var span = $( "span", a ); |
---|
627 | span.data( "label.tabs", span.html() ).html( o.spinner ); |
---|
628 | } |
---|
629 | |
---|
630 | this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, { |
---|
631 | url: url, |
---|
632 | success: function( r, s ) { |
---|
633 | self.element.find( self._sanitizeSelector( a.hash ) ).html( r ); |
---|
634 | |
---|
635 | // take care of tab labels |
---|
636 | self._cleanup(); |
---|
637 | |
---|
638 | if ( o.cache ) { |
---|
639 | $.data( a, "cache.tabs", true ); |
---|
640 | } |
---|
641 | |
---|
642 | self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); |
---|
643 | try { |
---|
644 | o.ajaxOptions.success( r, s ); |
---|
645 | } |
---|
646 | catch ( e ) {} |
---|
647 | }, |
---|
648 | error: function( xhr, s, e ) { |
---|
649 | // take care of tab labels |
---|
650 | self._cleanup(); |
---|
651 | |
---|
652 | self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) ); |
---|
653 | try { |
---|
654 | // Passing index avoid a race condition when this method is |
---|
655 | // called after the user has selected another tab. |
---|
656 | // Pass the anchor that initiated this request allows |
---|
657 | // loadError to manipulate the tab content panel via $(a.hash) |
---|
658 | o.ajaxOptions.error( xhr, s, index, a ); |
---|
659 | } |
---|
660 | catch ( e ) {} |
---|
661 | } |
---|
662 | } ) ); |
---|
663 | |
---|
664 | // last, so that load event is fired before show... |
---|
665 | self.element.dequeue( "tabs" ); |
---|
666 | |
---|
667 | return this; |
---|
668 | }, |
---|
669 | |
---|
670 | abort: function() { |
---|
671 | // stop possibly running animations |
---|
672 | this.element.queue( [] ); |
---|
673 | this.panels.stop( false, true ); |
---|
674 | |
---|
675 | // "tabs" queue must not contain more than two elements, |
---|
676 | // which are the callbacks for the latest clicked tab... |
---|
677 | this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) ); |
---|
678 | |
---|
679 | // terminate pending requests from other tabs |
---|
680 | if ( this.xhr ) { |
---|
681 | this.xhr.abort(); |
---|
682 | delete this.xhr; |
---|
683 | } |
---|
684 | |
---|
685 | // take care of tab labels |
---|
686 | this._cleanup(); |
---|
687 | return this; |
---|
688 | }, |
---|
689 | |
---|
690 | url: function( index, url ) { |
---|
691 | this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url ); |
---|
692 | return this; |
---|
693 | }, |
---|
694 | |
---|
695 | length: function() { |
---|
696 | return this.anchors.length; |
---|
697 | } |
---|
698 | }); |
---|
699 | |
---|
700 | $.extend( $.ui.tabs, { |
---|
701 | version: "1.8.17" |
---|
702 | }); |
---|
703 | |
---|
704 | /* |
---|
705 | * Tabs Extensions |
---|
706 | */ |
---|
707 | |
---|
708 | /* |
---|
709 | * Rotate |
---|
710 | */ |
---|
711 | $.extend( $.ui.tabs.prototype, { |
---|
712 | rotation: null, |
---|
713 | rotate: function( ms, continuing ) { |
---|
714 | var self = this, |
---|
715 | o = this.options; |
---|
716 | |
---|
717 | var rotate = self._rotate || ( self._rotate = function( e ) { |
---|
718 | clearTimeout( self.rotation ); |
---|
719 | self.rotation = setTimeout(function() { |
---|
720 | var t = o.selected; |
---|
721 | self.select( ++t < self.anchors.length ? t : 0 ); |
---|
722 | }, ms ); |
---|
723 | |
---|
724 | if ( e ) { |
---|
725 | e.stopPropagation(); |
---|
726 | } |
---|
727 | }); |
---|
728 | |
---|
729 | var stop = self._unrotate || ( self._unrotate = !continuing |
---|
730 | ? function(e) { |
---|
731 | if (e.clientX) { // in case of a true click |
---|
732 | self.rotate(null); |
---|
733 | } |
---|
734 | } |
---|
735 | : function( e ) { |
---|
736 | t = o.selected; |
---|
737 | rotate(); |
---|
738 | }); |
---|
739 | |
---|
740 | // start rotation |
---|
741 | if ( ms ) { |
---|
742 | this.element.bind( "tabsshow", rotate ); |
---|
743 | this.anchors.bind( o.event + ".tabs", stop ); |
---|
744 | rotate(); |
---|
745 | // stop rotation |
---|
746 | } else { |
---|
747 | clearTimeout( self.rotation ); |
---|
748 | this.element.unbind( "tabsshow", rotate ); |
---|
749 | this.anchors.unbind( o.event + ".tabs", stop ); |
---|
750 | delete this._rotate; |
---|
751 | delete this._unrotate; |
---|
752 | } |
---|
753 | |
---|
754 | return this; |
---|
755 | } |
---|
756 | }); |
---|
757 | |
---|
758 | })( jQuery ); |
---|