the browser-facing portion of osu!
at master 27 kB view raw
1/** 2 * jquery Tocify - v1.9.0 - 2013-10-01 3 * http://www.gregfranko.com/jquery.tocify.js/ 4 * Copyright (c) 2013 Greg Franko; 5 * Copyright (c) ppy Pty Ltd <contact@ppy.sh>; 6 * Licensed MIT */ 7import 'jquery-ui/ui/widget'; 8 9/* globals $, document, window */ 10var tocClassName = 'tocify'; 11var tocFocusClassName = 'tocify-focus'; 12var tocHoverClassName = 'tocify-hover'; 13var hideTocClassName = 'tocify-hide'; 14var headerClassName = 'tocify-header'; 15var headerClass = '.' + headerClassName; 16var subheaderClassName = 'tocify-subheader'; 17var subheaderClass = '.' + subheaderClassName; 18var itemClassName = 'tocify-item'; 19var itemClass = '.' + itemClassName; 20var extendPageClassName = 'tocify-extend-page'; 21var extendPageClass = '.' + extendPageClassName; 22 23// Calling the jQueryUI Widget Factory Method 24$.widget('toc.tocify', { 25 // _addCSSClasses 26 // -------------- 27 // Adds CSS classes to the newly generated table of contents HTML 28 _addCSSClasses() { 29 if (this.options.theme === 'jqueryui') { 30 // If the user wants a jqueryUI theme 31 this.focusClass = 'ui-state-default'; 32 this.hoverClass = 'ui-state-hover'; 33 // Adds the default styling to the dropdown list 34 this.element.addClass('ui-widget').find('.toc-title').addClass('ui-widget-header').end().find('li').addClass('ui-widget-content'); 35 } else if (this.options.theme === 'bootstrap') { 36 // If the user wants a twitterBootstrap theme 37 this.element.find(headerClass + ',' + subheaderClass).addClass('nav nav-list'); 38 this.focusClass = 'active'; 39 // If a user does not want a prebuilt theme 40 } else { 41 // Adds more neutral classes (instead of jqueryui) 42 this.focusClass = tocFocusClassName; 43 this.hoverClass = tocHoverClassName; 44 } 45 46 // Maintains chainability 47 return this; 48 }, 49 50 // _appendSubheaders 51 // --------------- 52 // Helps create the table of contents list by appending subheader elements 53 _appendSubheaders(self, ul) { 54 // The current element index 55 var index = $(this).index(self.options.selectors); 56 // Finds the previous header DOM element 57 var previousHeader = $(self.options.selectors).eq(index - 1); 58 var currentTagName = +$(this).prop('tagName').charAt(1); 59 var previousTagName = +previousHeader.prop('tagName').charAt(1); 60 61 if (currentTagName < previousTagName) { 62 // If the current header DOM element is smaller than the previous header DOM element or the first subheader 63 // Selects the last unordered list HTML found within the HTML element calling the plugin 64 self.element.find(subheaderClass + '[data-tag=' + currentTagName + ']').last().append(self._nestElements($(this), index)); 65 } else if (currentTagName === previousTagName) { 66 // If the current header DOM element is the same type of header(eg. h4) as the previous header DOM element 67 ul.find(itemClass).last().after(self._nestElements($(this), index)); 68 } else { 69 // Selects the last unordered list HTML found within the HTML element calling the plugin 70 ul.find(itemClass).last(). 71 // Appends an unorderedList HTML element to the dynamic `unorderedList` variable and sets a common class name 72 after($('<ul/>', { 73 class: subheaderClassName, 74 'data-tag': currentTagName, 75 })).next(subheaderClass). 76 // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin 77 append(self._nestElements($(this), index)); 78 } 79 }, 80 81 // _Create 82 // ------- 83 // Constructs the plugin. Only called once. 84 _create() { 85 var self = this; 86 self.extendPageScroll = true; 87 // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings) 88 self.items = []; 89 // Generates the HTML for the dynamic table of contents 90 self._generateToc(); 91 // Adds CSS classes to the newly generated table of contents HTML 92 self._addCSSClasses(); 93 self.webkit = (function() { 94 for (var prop in window) { 95 if (prop) { 96 if (prop.toLowerCase().indexOf('webkit') !== -1) { 97 return true; 98 } 99 } 100 } 101 102 return false; 103 }()); 104 105 // Adds jQuery event handlers to the newly generated table of contents 106 self._setEventHandlers(); 107 108 // Binding to the Window load event to make sure the correct scrollTop is calculated 109 $(window).on('load', function() { 110 // Sets the active TOC item 111 self._setActiveElement(true); 112 // Once all animations on the page are complete, this callback function will be called 113 $('html, body').promise().done(function() { 114 setTimeout(function() { 115 self.extendPageScroll = false; 116 }, 0); 117 }); 118 }); 119 }, 120 121 // _generateHashValue 122 // ------------------ 123 // Generates the hash value that will be used to refer to each item. 124 _generateHashValue(arr, self, index) { 125 var hashValue = ''; 126 var hashGeneratorOption = this.options.hashGenerator; 127 128 if (hashGeneratorOption === 'pretty') { 129 // prettify the text 130 hashValue = self.text().toLowerCase().replace(/\s/g, '-'); 131 // fix double hyphens 132 while (hashValue.indexOf('--') > -1) { 133 hashValue = hashValue.replace(/--/g, '-'); 134 } 135 // fix colon-space instances 136 while (hashValue.indexOf(':-') > -1) { 137 hashValue = hashValue.replace(/:-/g, '-'); 138 } 139 } else if (typeof hashGeneratorOption === 'function') { 140 // call the function 141 hashValue = hashGeneratorOption(self.text(), self); 142 } else { 143 // compact - the default 144 hashValue = self.text().replace(/\s/g, ''); 145 } 146 147 // add the index if we need to 148 if (arr.length) { 149 hashValue += '' + index; 150 } 151 152 // return the value 153 return hashValue; 154 }, 155 156 // _generateToc 157 // ------------ 158 // Generates the HTML for the dynamic table of contents 159 _generateToc() { 160 // Stores the plugin context in the self variable 161 var self = this; 162 // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above 163 var $firstElems; 164 // Instantiated variable that will store the top level newly created unordered list DOM element 165 var ul; 166 var ignoreSelector = self.options.ignoreSelector; 167 // If the selectors option has a comma within the string 168 if (this.options.selectors.indexOf(',') !== -1) { 169 // Grabs the first selector from the string 170 $firstElems = $(this.options.context).find(this.options.selectors.replace(/ /g, '').substr(0, this.options.selectors.indexOf(','))); 171 } else { 172 // If the selectors option does not have a comma within the string 173 // Grabs the first selector from the string and makes sure there are no spaces 174 $firstElems = $(this.options.context).find(this.options.selectors.replace(/ /g, '')); 175 } 176 177 if (!$firstElems.length) { 178 self.element.addClass(hideTocClassName); 179 return; 180 } 181 182 self.element.addClass(tocClassName); 183 184 // Loops through each top level selector 185 $firstElems.each(function(index, firstElem) { 186 const $firstElem = $(firstElem); 187 188 // If the element matches the ignoreSelector then we skip it 189 if ($firstElem.is(ignoreSelector)) { 190 return; 191 } 192 193 // Creates an unordered list HTML element and adds a dynamic ID and standard class name 194 ul = $('<ul/>', { 195 class: headerClassName, 196 id: headerClassName + index, 197 }). 198 // Appends a top level list item HTML element to the previously created HTML header 199 append(self._nestElements($firstElem, index)); 200 201 // Add the created unordered list element to the HTML element calling the plugin 202 self.element.append(ul); 203 204 // Finds all of the HTML tags between the header and subheader elements 205 $firstElem.nextUntil(firstElem.nodeName.toLowerCase()).each(function(_idx, el) { 206 const $el = $(el); 207 // If there are no nested subheader elemements 208 if ($el.find(self.options.selectors).length === 0) { 209 // Loops through all of the subheader elements 210 $el.filter(self.options.selectors).each(function(__idx, subheader) { 211 // If the element matches the ignoreSelector then we skip it 212 if ($(subheader).is(ignoreSelector)) { 213 return; 214 } 215 216 self._appendSubheaders.call(subheader, self, ul); 217 }); 218 } else { 219 // If there are nested subheader elements 220 // Loops through all of the subheader elements 221 $el.find(self.options.selectors).each(function(__idx, subheader) { 222 // If the element matches the ignoreSelector then we skip it 223 if ($(subheader).is(ignoreSelector)) { 224 return; 225 } 226 227 self._appendSubheaders.call(subheader, self, ul); 228 }); 229 } 230 }); 231 }); 232 }, 233 234 // _nestElements 235 // ------------- 236 // Helps create the table of contents list by appending nested list items 237 _nestElements(self, index) { 238 var arr; var item; var hashValue; 239 240 arr = $.grep(this.items, function(i) { 241 return i === self.text(); 242 }); 243 244 if (arr.length) { 245 // If there is already a duplicate TOC item 246 // Adds the current TOC item text and index (for slight randomization) to the internal array 247 this.items.push(self.text() + index); 248 } else { 249 // If there not a duplicate TOC item 250 // Adds the current TOC item text to the internal array 251 this.items.push(self.text()); 252 } 253 254 hashValue = this._generateHashValue(arr, self, index); 255 256 // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin 257 item = $('<li/>', { 258 // Sets a common class name to the list item 259 class: itemClassName, 260 'data-unique': hashValue, 261 }).append($('<a/>', { 262 text: self.text(), 263 })); 264 265 // Adds an HTML anchor tag before the currently traversed HTML element 266 self.before($('<div/>', { 267 'data-unique': hashValue, 268 // Sets a name attribute on the anchor tag to the text of the currently traversed HTML element (also making sure that all whitespace is replaced with an underscore) 269 name: hashValue, 270 })); 271 272 return item; 273 }, 274 275 // _scrollTo 276 // --------- 277 // Scrolls to a specific element 278 _scrollTo(elem) { 279 var self = this; 280 var duration = self.options.smoothScroll || 0; 281 var scrollTo = self.options.scrollTo; 282 var currentDiv = $('div[data-unique="' + elem.attr('data-unique') + '"]'); 283 284 if (!currentDiv.length) { 285 return self; 286 } 287 288 // Once all animations on the page are complete, this callback function will be called 289 $('html, body').promise().done(function() { 290 // Animates the html and body element scrolltops 291 $('html, body').animate({ 292 // Sets the jQuery `scrollTop` to the top offset of the HTML div tag that matches the current list item's `data-unique` tag 293 scrollTop: currentDiv.offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + 'px', 294 }, { 295 // Sets the smoothScroll animation time duration to the smoothScrollSpeed option 296 duration, 297 }); 298 }); 299 300 // Maintains chainability 301 return self; 302 }, 303 304 _setActiveElement(pageload) { 305 var self = this; 306 var hash = window.location.hash.substring(1); 307 var elem = self.element.find('li[data-unique="' + hash + '"]'); 308 309 if (hash.length) { 310 // Removes highlighting from all of the list item's 311 self.element.find('.' + self.focusClass).removeClass(self.focusClass); 312 // Highlights the current list item that was clicked 313 elem.addClass(self.focusClass); 314 315 if (self.options.showAndHide) { 316 // If the showAndHide option is true 317 // Triggers the click event on the currently focused TOC item 318 elem.click(); 319 } 320 } else { 321 // Removes highlighting from all of the list item's 322 self.element.find('.' + self.focusClass).removeClass(self.focusClass); 323 324 if (!hash.length && pageload && self.options.highlightDefault) { 325 // Highlights the first TOC item if no other items are highlighted 326 self.element.find(itemClass).first().addClass(self.focusClass); 327 } 328 } 329 330 return self; 331 }, 332 333 // _setEventHandlers 334 // ---------------- 335 // Adds jQuery event handlers to the newly generated table of contents 336 _setEventHandlers() { 337 // Stores the plugin context in the self variable 338 var self = this; 339 340 // Event delegation that looks for any clicks on list item elements inside of the HTML element calling the plugin 341 this.element.on('click.tocify', 'li', function(event) { 342 const $target = $(event.currentTarget); 343 344 if (self.options.history) { 345 window.location.hash = $target.attr('data-unique'); 346 } 347 348 // Removes highlighting from all of the list item's 349 self.element.find('.' + self.focusClass).removeClass(self.focusClass); 350 351 // Highlights the current list item that was clicked 352 $target.addClass(self.focusClass); 353 354 // If the showAndHide option is true 355 if (self.options.showAndHide) { 356 var elem = $('li[data-unique="' + $target.attr('data-unique') + '"]'); 357 self._triggerShow(elem); 358 } 359 self._scrollTo($target); 360 }); 361 362 // Mouseenter and Mouseleave event handlers for the list item's within the HTML element calling the plugin 363 this.element.find('li').on({ 364 // Mouseenter event handler 365 'mouseenter.tocify'() { 366 // Adds a hover CSS class to the current list item 367 $(this).addClass(self.hoverClass); 368 369 // Makes sure the cursor is set to the pointer icon 370 $(this).css('cursor', 'pointer'); 371 }, 372 373 // Mouseleave event handler 374 'mouseleave.tocify'() { 375 if (self.options.theme !== 'bootstrap') { 376 // Removes the hover CSS class from the current list item 377 $(this).removeClass(self.hoverClass); 378 } 379 }, 380 }); 381 382 // only attach handler if needed (expensive in IE) 383 if (self.options.extendPage || self.options.highlightOnScroll || self.options.scrollHistory || self.options.showAndHideOnScroll) { 384 // Window scroll event handler 385 $(window).on('scroll.tocify', function() { 386 // Once all animations on the page are complete, this callback function will be called 387 $('html, body').promise().done(function() { 388 // Stores how far the user has scrolled 389 var winScrollTop = $(window).scrollTop(); 390 // Stores the height of the window 391 var winHeight = $(window).height(); 392 // Stores the height of the document 393 var docHeight = $(document).height(); 394 var scrollHeight = $('body')[0].scrollHeight; 395 // Instantiates a variable that will be used to hold a selected HTML element 396 var elem; 397 var lastElem; 398 var lastElemOffset; 399 var currentElem; 400 401 if (self.options.extendPage) { 402 403 // If the user has scrolled to the bottom of the page and the last toc item is not focused 404 if ((self.webkit && winScrollTop >= scrollHeight - winHeight - self.options.extendPageOffset) || (!self.webkit && winHeight + winScrollTop > docHeight - self.options.extendPageOffset)) { 405 if (!$(extendPageClass).length) { 406 lastElem = $('div[data-unique="' + $(itemClass).last().attr('data-unique') + '"]'); 407 408 if (!lastElem.length) return; 409 410 // Gets the top offset of the page header that is linked to the last toc item 411 lastElemOffset = lastElem.offset().top; 412 413 // Appends a div to the bottom of the page and sets the height to the difference of the window scrollTop and the last element's position top offset 414 $(self.options.context).append($('<div />', { 415 class: extendPageClassName, 416 'data-unique': extendPageClassName, 417 height: Math.abs(lastElemOffset - winScrollTop) + 'px', 418 })); 419 420 if (self.extendPageScroll) { 421 currentElem = self.element.find('li.active'); 422 self._scrollTo($('div[data-unique="' + currentElem.attr('data-unique') + '"]')); 423 } 424 } 425 } 426 } 427 428 // The zero timeout ensures the following code is run after the scroll events 429 setTimeout(function() { 430 // Stores the distance to the closest anchor 431 var closestAnchorDistance = null; 432 // Stores the index of the closest anchor 433 var closestAnchorIdx = null; 434 // Keeps a reference to all anchors 435 var anchors = $(self.options.context).find('div[data-unique]'); 436 var anchorText; 437 438 // Determines the index of the closest anchor 439 anchors.each(function(idx, el) { 440 const $el = $(el); 441 var distance = Math.abs(($el.next().length ? $el.next() : $el).offset().top - winScrollTop - self.options.highlightOffset); 442 if (closestAnchorDistance == null || distance < closestAnchorDistance) { 443 closestAnchorDistance = distance; 444 closestAnchorIdx = idx; 445 } else { 446 return false; 447 } 448 }); 449 450 anchorText = $(anchors[closestAnchorIdx]).attr('data-unique'); 451 452 // Stores the list item HTML element that corresponds to the currently traversed anchor tag 453 elem = $('li[data-unique="' + anchorText + '"]'); 454 455 // If the `highlightOnScroll` option is true and a next element is found 456 if (self.options.highlightOnScroll && elem.length) { 457 // Removes highlighting from all of the list item's 458 self.element.find('.' + self.focusClass).removeClass(self.focusClass); 459 460 // Highlights the corresponding list item 461 elem.addClass(self.focusClass); 462 } 463 464 if (self.options.scrollHistory) { 465 if (window.location.hash !== '#' + anchorText) { 466 window.history.replaceState(null, '', '#' + anchorText); 467 } 468 } 469 470 // If the `showAndHideOnScroll` option is true 471 if (self.options.showAndHideOnScroll && self.options.showAndHide) { 472 self._triggerShow(elem, true); 473 } 474 }, 0); 475 }); 476 }); 477 } 478 }, 479 480 // _triggerShow 481 // ------------ 482 // Determines what elements get shown on scroll and click 483 _triggerShow(elem, scroll) { 484 var self = this; 485 486 if (elem.parent().is(headerClass) || elem.next().is(subheaderClass)) { 487 // If the current element's parent is a header element or the next element is a nested subheader element 488 // Shows the next sub-header element 489 self.show(elem.next(subheaderClass), scroll); 490 } else if (elem.parent().is(subheaderClass)) { 491 // If the current element's parent is a subheader element 492 // Shows the parent sub-header element 493 self.show(elem.parent(), scroll); 494 } 495 496 // Maintains chainability 497 return self; 498 }, 499 500 // Hide 501 // ---- 502 // Closes the current sub-header 503 hide(elem) { 504 // Stores the plugin context in the `self` variable 505 var self = this; 506 507 // Determines what jQuery effect to use 508 switch (self.options.hideEffect) { 509 // Uses `no effect` 510 case 'none': 511 elem.hide(); 512 break; 513 // Uses the jQuery `hide` special effect 514 case 'hide': 515 elem.hide(self.options.hideEffectSpeed); 516 break; 517 // Uses the jQuery `slideUp` special effect 518 case 'slideUp': 519 elem.slideUp(self.options.hideEffectSpeed); 520 break; 521 // Uses the jQuery `fadeOut` special effect 522 case 'fadeOut': 523 elem.fadeOut(self.options.hideEffectSpeed); 524 break; 525 // If none of the above options were passed, then a `jqueryUI hide effect` is expected 526 default: 527 elem.hide(); 528 break; 529 } 530 531 // Maintains chainablity 532 return self; 533 }, 534 535 // These options will be used as defaults 536 options: { 537 538 // **context**: Accepts String: Any jQuery selector 539 // The container element that holds all of the elements used to generate the table of contents 540 context: 'body', 541 542 // **extendPage**: Accepts a boolean: true or false 543 // If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased 544 extendPage: true, 545 546 // **extendPageOffset**: Accepts a number: pixels 547 // How close to the bottom of the page a user must scroll before the page is extended 548 extendPageOffset: 100, 549 550 // **hashGenerator**: How the hash value (the anchor segment of the URL, following the 551 // # character) will be generated. 552 // 553 // "compact" (default) - #CompressesEverythingTogether 554 // "pretty" - #looks-like-a-nice-url-and-is-easily-readable 555 // function(text, element){} - Your own hash generation function that accepts the text as an 556 // argument, and returns the hash value. 557 hashGenerator: 'compact', 558 559 // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp" 560 // Used to hide any of the table of contents nested items 561 hideEffect: 'slideUp', 562 563 // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 564 // The time duration of the hide animation 565 hideEffectSpeed: 'medium', 566 567 // **highlightDefault**: Accepts a boolean: true or false 568 // Set's the first TOC item as active if no other TOC item is active. 569 highlightDefault: true, 570 571 // **highlightOffset**: Accepts a number 572 // The offset distance in pixels to trigger the next active table of contents item 573 highlightOffset: 40, 574 575 // **highlightOnScroll**: Accepts a boolean: true or false 576 // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling 577 highlightOnScroll: true, 578 579 // **history**: Accepts a boolean: true or false 580 // Adds a hash to the page url to maintain history 581 history: true, 582 583 // **ignoreSelector**: Accepts String: Any jQuery selector 584 // A selector to any element that would be matched by selectors that you wish to be ignored 585 ignoreSelector: null, 586 587 // **scrollHistory**: Accepts a boolean: true or false 588 // Adds a hash to the page url, to maintain history, when scrolling to a TOC item 589 scrollHistory: false, 590 591 // **scrollTo**: Accepts Number (pixels) 592 // The amount of space between the top of page and the selected table of contents item after the page has been scrolled 593 scrollTo: 0, 594 595 // **selectors**: Accepts an Array of Strings: Any jQuery selectors 596 // The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure 597 selectors: 'h1, h2, h3', 598 599 // **showAndHide**: Accepts a boolean: true or false 600 // Used to determine if elements should be shown and hidden 601 showAndHide: true, 602 603 // **showAndHideOnScroll**: Accepts a boolean: true or false 604 // Determines if table of contents nested items should be shown and hidden while scrolling 605 showAndHideOnScroll: true, 606 607 // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown" 608 // Used to display any of the table of contents nested items 609 showEffect: 'slideDown', 610 611 // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 612 // The time duration of the show animation 613 showEffectSpeed: 'medium', 614 615 // **smoothScroll**: Accepts a boolean: true or false 616 // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page 617 smoothScroll: true, 618 619 // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" 620 // The time duration of the smoothScroll animation 621 smoothScrollSpeed: 'medium', 622 623 // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none" 624 // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents 625 theme: 'bootstrap', 626 }, 627 628 // setOption 629 // --------- 630 // Sets a single Tocify option after the plugin is invoked 631 setOption() { 632 // Calls the jQueryUI Widget Factory setOption method 633 $.Widget.prototype._setOption.apply(this, arguments); 634 }, 635 636 // setOptions 637 // ---------- 638 // Sets a single or multiple Tocify options after the plugin is invoked 639 setOptions() { 640 // Calls the jQueryUI Widget Factory setOptions method 641 $.Widget.prototype._setOptions.apply(this, arguments); 642 }, 643 644 // Show 645 // ---- 646 // Opens the current sub-header 647 show(elem) { 648 // Stores the plugin context in the `self` variable 649 var self = this; 650 651 // If the sub-header is not already visible 652 if (!elem.is(':visible')) { 653 654 if (!elem.find(subheaderClass).length && !elem.parent().is(headerClass) && !elem.parent().is(':visible')) { 655 // If the current element does not have any nested subheaders, is not a header, and its parent is not visible 656 // Sets the current element to all of the subheaders within the current header 657 elem = elem.parents(subheaderClass).add(elem); 658 } else if (!elem.children(subheaderClass).length && !elem.parent().is(headerClass)) { 659 // If the current element does not have any nested subheaders and is not a header 660 // Sets the current element to the closest subheader 661 elem = elem.closest(subheaderClass); 662 } 663 664 // Determines what jQuery effect to use 665 switch (self.options.showEffect) { 666 // Uses `no effect` 667 case 'none': 668 elem.show(); 669 break; 670 // Uses the jQuery `show` special effect 671 case 'show': 672 elem.show(self.options.showEffectSpeed); 673 break; 674 // Uses the jQuery `slideDown` special effect 675 case 'slideDown': 676 elem.slideDown(self.options.showEffectSpeed); 677 break; 678 // Uses the jQuery `fadeIn` special effect 679 case 'fadeIn': 680 elem.fadeIn(self.options.showEffectSpeed); 681 break; 682 // If none of the above options were passed, then a `jQueryUI show effect` is expected 683 default: 684 elem.show(); 685 break; 686 } 687 688 } 689 690 if (elem.parent().is(headerClass)) { 691 // If the current subheader parent element is a header 692 // Hides all non-active sub-headers 693 self.hide($(subheaderClass).not(elem)); 694 } else { 695 // If the current subheader parent element is not a header 696 // Hides all non-active sub-headers 697 self.hide($(subheaderClass).not(elem.closest(headerClass).find(subheaderClass).not(elem.siblings()))); 698 } 699 700 // Maintains chainablity 701 return self; 702 }, 703 704 // Plugin version 705 version: '1.9.0', 706});