1/** 2 * Zebra_Accordion 3 * 4 * A tiny (3KB minified) accordion plugin for jQuery. 5 * 6 * It transforms a basic definition list, without requiring any other specific markup, into a small-footprint, easily 7 * configurable, fully customizable, cross-browser accordion widget, useful for better organizing larger groups of content. 8 * 9 * Features: 10 * 11 * - no additional markup required other than a basic definition list; 12 * - easily customizable through CSS; 13 * - works with both fixed and fluid (responsive) layouts; 14 * - can be configured to work so that only a single can be expanded at a time, or so that all tabs may be 15 * expanded/collapsed; 16 * - can be configured to work so tabs expand on mouse over; 17 * - when, after expanding a tab, part of its content is outside the viewport, it automatically scrolls the browser's 18 * window so that the tab's content is visible; 19 * - callback functions can be used for further customizations; 20 * - works in all major browsers (Firefox, Opera, Safari, Chrome, Internet Explorer 6, 7, 8, 9) 21 * 22 * Visit {@link http://stefangabos.ro/jquery/zebra-accordion/} for more information. 23 * 24 * For more resources visit {@link http://stefangabos.ro/} 25 * 26 * @author Stefan Gabos <[email protected]> 27 * @version 1.2.2 (last revision: November 28, 2013) 28 * @copyright (c) 2011 - 2013 Stefan Gabos 29 * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE 30 * @package Zebra_Accordion 31 */ 32;(function($) { 33 34 $.Zebra_Accordion = function(el, options) { 35 36 var defaults = { 37 38 animate_opacity: true, // Should the content block's opacity be also animated? 39 // 40 // Default is TRUE 41 42 collapsible: false, // If set to TRUE, an open block can also be c
42ollapsed 43 // - in this case, all blocks can be collapsed; if set 44 // to FALSE, an open block can be collapsed only by 45 // opening another block - in this case, only a single 46 // block is open at any given moment; 47 // 48 // Default is FALSE 49 50 expanded_class: 'Zebra_Accordion_Expanded', // The name of the class to append to the "title" 51 // element when its associated content block is 52 // expanded. 53 // 54 // Can be used for customizing the aspect of the opened 55 // tab to give better visual feedback to the users. 56 // 57 // Default is "Zebra_Accordion_Expanded" 58 59 hide_speed: 400, // The speed (in milliseconds) to use when collapsing 60 // content blocks. 61 // 62 // Default is 400 63 64 scroll_speed: 600, // If a content block's content is not entirely visible 65 // after it is expanded, the window will be scrolled so 66 // so that the entire content of the content block is 67 // visible (if it is possible). 68 // 69 // This value represents the speed (in milliseconds) to 70 // use for scrolling. 71 // 72 // Default is 600 73 74 show_speed: 400, // The speed (in milliseconds) to use when expanding 75 // content blocks. 76 // 77 // Default is 400 78 79 show: 0, // The index (0 based) of the content block to be 80 // expanded by default. 81 // 82 // The value of this property can also be boolean FALSE, 83 // indicating that all tabs should be collapsed by default. 84 // 85 // If the value of the "collapsible" property is TRUE, 86 // the value of this property can also be boolean TRUE, 87 // indicating that all tabs should be expanded by default, 88 // or an array with the indexes of tabs to be expanded 89 // by default. 90 // 91 // Default is 0 92 93 toggle_on_mouseover: false, // Set this to TRUE if content blocks should be expanded 94 // when hovering their associated "titles". 95 // 96 // If "collapsible" is TRUE then this property will 97 // always be FALSE! 98 // 99 // Default is FALSE; 100 101 onBeforeClose: null, // Event fired before a content block is collapsed. 102 // 103 // The callback function (if any) receives as arguments 104 // the closed item's number (0 based), the title element 105 // and the content block element. 106 // 107 onBeforeOpen: null, // Event fired before a content block is expanded. 108 // 109 // The callback function (if any) receives as arguments 110 // the closed item's number (0 based), the title element 111 // and the content block element. 112 113 onClose: null, // Event fired after a content block is collapsed. 114 // 115 // The callback function (if any) receives as arguments 116 // the closed item's number (0 based), the title element 117 // and the content block element. 118 119 onOpen: null // Event fired after a content block is expanded. 120 // 121 // The callback function (if any) receives as arguments 122 // the opened item's number (0 based), the title element 123 // and the content block element. 124 125 }; 126 127 var 128 129 // to avoid confusions, we use "plugin" to reference the current instance of the plugin 130 plugin = this, 131 132 // private lookup arrays 133 $titles = null, 134 $blocks = null, 135 136 titles = [], 137 blocks = []; 138 139 plugin.settings = {}; 140 141 /** 142 * Constructor method 143 * 144 * @return object Returns a reference to the plugin 145 */ 146 var init = function() { 147 148 // the plugin's final properties are the merged default and user-prov
148ided options (if any) 149 plugin.settings = $.extend({}, defaults, options); 150 151 var $element = $(el); // reference to the jQuery version of DOM element the plugin is attached to 152 153 $titles = $('dt', $element); // references to the title elements 154 $blocks = $('dd', $element); // references to the content blocks 155 156 // iterate through the title elements and get some information about each element 157 _get_titles_info(); 158 159 // iterate through the content block elements and get some information about each element 160 _get_blocks_info(); 161 162 // if a content block is to be shown by default 163 if (plugin.settings.show !== false) { 164 165 // if any number of content blocks can be expanded/collapsed, and by default we have to expand a certain 166 // set of content blocks, or all 167 if (plugin.settings.collapsible && ($.isArray(plugin.settings.show) || plugin.settings.show === true)) { 168 169 // if we have to expand all content blocks 170 if (plugin.settings.show === true) 171 172 // expand all content blocks 173 for (var i = 0; i < $titles.length; i++) plugin.show(i, true, true); 174 175 // if we only have to expand certain content blocks 176 else 177 178 // iterate through the content blocks that need to be expanded 179 $.each(plugin.settings.show, function(index) { 180 181 // expand each content block 182 plugin.show(plugin.settings.show[index], true, true); 183 184 }); 185 186 // otherwise, show the default content block 187 } else plugin.show(plugin.settings.show, true, true); 188 189 } 190 191 // run a function whenever the browser's window is resized 192 $(window).bind('resize', function() { 193 194 // by default, we assume that there's no tab opened 195 var open = []; 196 197 // iterate through the title elements 198 $titles.each(function(index) { 199 200 // reference to the title element 201 var $title = $(this); 202 203 // if we find an opened tab, save the tab's number for later 204 if ($title.hasClass(plugin.settings.expanded_class)) open.push(index); 205 206 // set the title element's "style" attribute back to its original state (before running the plugin) 207 $title.attr('style', titles[index].style); 208 209 }); 210 211 // iterate through the title elements and get some information about each element 212 // also, make sure we don't re-bind callback functions to events 213 _get_titles_info(false); 214 215 // iterate through the content block elements 216 $blocks.each(function(index) { 217 218 // set the content element's "style" attribute back to its original state (before running the plugin) 219 $(this).attr('style', blocks[index].style); 220 221 }); 222 223 // iterate through the content elements and get some information about each element 224 _get_blocks_info(); 225 226 // if there were open tabs 227 if (open.length > 0) 228 229 // re-open them now 230 $.each(open, function(index) { 231 232 plugin.show(open[index], true, true); 233 234 }); 235 236 }); 237 238 }; 239 240 /** 241 * Expands a content block. 242 * 243 * @param integer index The 0-based index of the content block to expand. 244 * 245 * @param boolean noFx (Optional) If set to TRUE, the content block will be instantly expanded without 246 * animation. 247 * 248 * Default is FALSE. 249 * 250 * @param boolean noScroll (Optional) If set to TRUE, the browser window will not be scrolled to the newly 251 * expanded content block. 252 * 253 * Default is FALSE. 254 * @return void 255 */ 256 plugin.show = function(index, noFx, noScroll) { 257 258 // if "index" is an integer, greater than 0 and lesser than the total number of items 259 if (null !== new String(index).match(/^[0-9]+$/) && index >= 0 && index <= blocks.length - 1) { 260 261 var $title = $($titles[index]), // reference to the title element 262 $block = $($blocks[index]), // reference to the content block element 263 block = blocks[index]; // get the block's properties 264 265 // if a callback function needs to be called before expanding the content block 266 if (plugin.settings.onBeforeOpen && typeof plugin.settings.onBeforeOpen == 'function') 267 268 // execute the callback function 269 plugin.settings.onBeforeOpen(index, $title, $block); 270 271 // if any block can can be expanded/collapsed at any time 272 // and current block is already expanded, collapse it instead 273 if (plugin.settings.collapsible && $block.height() > 0) return plugin.hide(index, noFx); 274 275 // if only a single block can be expanded at a time 276 else if (!plugin.settings.collapsible) 277 278 // iterate through the content blocks 279 $blocks.each(function(key) { 280 281 // if not the block that we are about to expand 282 // collapse the content block
283 if (key != index) plugin.hide(key, noFx); 284 285 }); 286 287 // add an extra class to the title element, to indicate that the element is expanded 288 // useful for custom styling of the title element, to give a better visual feedback to the users 289 $title.addClass(plugin.settings.expanded_class); 290 291 // set the content block's "display" property to "block" 292 $block.css('display', 'block'); 293 294 // stop any ongoing animation on the current content block 295 $block.stop(); 296 297 // expand the indicated content block 298 $block.animate({ 299 300 'height': block.height, 301 'paddingTop': block.paddingTop, 302 'paddingBottom': block.paddingBottom, 303 'marginTop': block.marginTop, 304 'marginBottom': block.marginBottom, 305 'opacity': 1 306 307 // using the speed as indicated in the settings 308 }, (noFx ? 0 : plugin.settings.show_speed), 309 310 // once the animation is complete 311 function() { 312 313 // if a callback function needs to be called after opening the content block 314 if (plugin.settings.onOpen && typeof plugin.settings.onOpen == 'function') 315 316 // execute the callback function 317 plugin.settings.onOpen(index, $title, $block); 318 319 // if scrolling is not explicitly disabled 320 if (!noScroll) { 321 322 var title_top = Math.round($title.offset().top), // the title's "top" position 323 title_height = titles[index].height, // the title's height 324 block_height = block.outerHeight, // the content block's height 325 total_height = title_top + title_height + block_height, // item's total height 326 viewport_height = $(window).height(), // visible area in the browser 327 viewport_scroll = $(window).scrollTop(), // how much is the page scrolled down (from the top) 328 offset = null; 329 330 // if a content block's bottom goes out of the view 331 if (total_height > viewport_height + viewport_scroll) { 332 333 // this is how much the page needs to be scrolled down (from the top) so that the content is visible 334 offset = total_height - viewport_height; 335 336 // but, if that would mean that the title would end up above the visible area 337 // better to scroll to the title instead 338 if (offset > title_top) offset = title_top; 339 340 } 341 342 // if title is above the visible area, scroll back up, so that the title becomes visible 343 if (title_top < viewport_scroll) offset = title_top; 344 345 // if we need to scroll the content 346 if (offset) 347 348 // smoothly scroll the page 349 $('html, body').animate({ 350 351 scrollTop: offset 352 353 // using the speed as indicated in the settings 354 }, plugin.settings.scroll_speed); 355 356 } 357 358 }); 359 360 } 361 362 }; 363 364 /** 365 * Collapses a content block. 366 * 367 * @param integer index The 0-based index of the content block to collapse. 368 * 369 * @param boolean noFx (Optional) If set to TRUE, the content block will be instantly collapsed without 370 * animation. 371 * 372 * Default is FALSE. 373 * 374 * @return void 375 */ 376 plugin.hide = function(index, noFx) { 377 378 // if "index" is an integer, greater than 0 and lesser than the total number of items, and the respective block is not already collapsed 379 if (null !== new String(index).match(/^[0-9]+$/) && index >= 0 && index <= blocks.length - 1) { 380 381 var $title = $($titles[index]), // reference to the title element 382 $block = $($blocks[index]), // reference to the content block element 383 block = blocks[index]; // get the block's properties 384 385 // if a callback function needs to be called before collapsing the content block 386 if (plugin.settings.onBeforeClose && typeof plugin.settings.onBeforeClose == 'function') 387 388 // execute the callback function 389 plugin.settings.onBeforeClose(index, $title, $block); 390 391 // remove the extra class added to the title element when the associated block was expanded 392 $title.removeClass(plugin.settings.expanded_class); 393 394 // stop any ongoing animation for the current content block 395 $block.stop(); 396 397 // supress top and bottom borders 398 $block.css({ 399 'borderTopWidth': 0, 400 'borderBottomWidth': 0 401 }); 402 403 // hide the element 404 $block.animate({ 405 406 'height': 0, 407 'paddingTop': 0, 408 'paddingBottom': 0, 409 'marginTop': 0, 410 'marginBottom': 0, 411 'opacity': (plugin.settings.animate_opacity ? 0 : 1) 412 413 // using the speed as indicated in the settings 414 }, (noFx ? 0 : plugin.settings.hide_speed), 415 416 // once the animation is complete 417 function() { 418 419 // if a callback function needs to be called after closing the content block 420 if (plugin.settings.onClose && typeof plugin.settings.onClose == 'function') 421 422 // execute the callback function 423 plugin.settings.onClose(index, $title, $block); 424 425 // set some of content block element's CSS properties 426 $(this).css({ 427 'display': 'none', 428 'visibility': 'visible', 429 'borderTopWidth': block.borderTopWidth, 430 'borderBottomWidth': block.borderBottomWidth 431 });
432 433 }); 434 435 } 436 437 }; 438 439 /** 440 * Gets some CSS properties for the accordion's content blocks 441 * 442 * @return void 443 * 444 * @access private 445 */ 446 var _get_blocks_info = function() { 447 448 // reset the lookup array 449 blocks = []; 450 451 // iterate through the content blocks 452 $blocks.each(function(index) { 453 454 // reference to the content block jQuery object 455 var $block = $(this); 456 457 // temporary make set content block's "display" property to "block", 458 // in order to be able to get some of the element's CSS properties 459 $block.css({ 460 'visibility': 'hidden', 461 'display': 'block' 462 }); 463 464 // get some of the element's CSS properties 465 // needed to correctly expand/collapse the block 466 // and add them to our lookup array 467 blocks.push({ 468 'height': $block.height(), 469 'outerHeight': $block.outerHeight(), 470 'paddingTop': _int($block.css('paddingTop')), 471 'paddingBottom': _int($block.css('paddingBottom')), 472 'marginTop': _int($block.css('marginTop')), 473 'marginBottom': _int($block.css('marginBottom')), 474 'borderTopWidth': _int($block.css('borderTopWidth')), 475 'borderBottomWidth': _int($block.css('borderBottomWidth')), 476 'style': $block.attr('style') // element's original style (if any) 477 }); 478 479 // all blocks are collapsed by default 480 plugin.hide(index, true); 481 482 }); 483 484 }; 485 486 /** 487 * Gets some CSS properties for the accordion's title blocks 488 * 489 * @return void 490 * 491 * @access private 492 */ 493 var _get_titles_info = function(nobind) { 494 495 // reset the lookup array 496 titles = []; 497 498 // iterate through the content titles 499 $titles.each(function(index) { 500 501 var 502 503 // reference to the element 504 $title = $(this), 505 506 // the event that should trigger content blocks expansion/collapse 507 event = !plugin.settings.collapsible && plugin.settings.toggle_on_mouseover ? 508 'mouseover' : 509 'click'; 510 511 // get some of the element's CSS properties 512 // needed to correctly expand/collapse the block 513 // and add them to our lookup array 514 titles.push({ 515 'height': $title.outerHeight(), // the title's height, including margins and padding 516 'style': $title.attr('style') // the element's original style attribute (if any) 517 }); 518 519 // if we need to handle the required event 520 // (this method may also be called internally upon resizing of the browser window 521 // case in which we don't need to re-attach the function to the required event) 522 if (undefined === nobind) 523 524 // handle the required event (click or mouseover - see above) 525 $title.bind(event, function() { 526 527 // show the associated content block 528 plugin.show(index); 529 530 }); 531 532 }); 533 534 }; 535 536 /** 537 * A wrapper to JavaScript's parseInt() function. 538 * 539 * @return int Returns the integer representation of the string given as argument 540 * 541 * @access private 542 */ 543 var _int = function(value) { 544 545 // convert value to an integer 546 value = parseInt(value, 10); 547 548 // if result is not a number (NaN) return 0, or the converted value otherwise 549 return isNaN(value) ? 0 : value; 550 551 }; 552
553 // fire it up! 554 init(); 555 556 }; 557 558})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.