Style changes for the Use cases.
[yaffs-website] / web / libraries / jquery.tocify.js-master / src / javascripts / jquery.tocify.js
1 /* jquery Tocify - v1.9.0 - 2013-10-01
2 * http://www.gregfranko.com/jquery.tocify.js/
3 * Copyright (c) 2013 Greg Franko; Licensed MIT */
4
5 // Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic.  I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE.
6 (function(tocify) {
7
8     // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
9     "use strict";
10
11     // Calls the second IIFE and locally passes in the global jQuery, window, and document objects
12     tocify(window.jQuery, window, document);
13
14 }
15
16 // Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable.  The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set.  All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript.
17 (function($, window, document, undefined) {
18
19     // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/)
20     "use strict";
21
22     var tocClassName = "tocify",
23         tocClass = "." + tocClassName,
24         tocFocusClassName = "tocify-focus",
25         tocHoverClassName = "tocify-hover",
26         hideTocClassName = "tocify-hide",
27         hideTocClass = "." + hideTocClassName,
28         headerClassName = "tocify-header",
29         headerClass = "." + headerClassName,
30         subheaderClassName = "tocify-subheader",
31         subheaderClass = "." + subheaderClassName,
32         itemClassName = "tocify-item",
33         itemClass = "." + itemClassName,
34         extendPageClassName = "tocify-extend-page",
35         extendPageClass = "." + extendPageClassName;
36
37     // Calling the jQueryUI Widget Factory Method
38     $.widget("toc.tocify", {
39
40         //Plugin version
41         version: "1.9.0",
42
43         // These options will be used as defaults
44         options: {
45
46             // **context**: Accepts String: Any jQuery selector
47             // The container element that holds all of the elements used to generate the table of contents
48             context: "body",
49
50             // **ignoreSelector**: Accepts String: Any jQuery selector
51             // A selector to any element that would be matched by selectors that you wish to be ignored
52             ignoreSelector: null,
53
54             // **selectors**: Accepts an Array of Strings: Any jQuery selectors
55             // 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
56             selectors: "h1, h2, h3",
57
58             // **showAndHide**: Accepts a boolean: true or false
59             // Used to determine if elements should be shown and hidden
60             showAndHide: true,
61
62             // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown"
63             // Used to display any of the table of contents nested items
64             showEffect: "slideDown",
65
66             // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
67             // The time duration of the show animation
68             showEffectSpeed: "medium",
69
70             // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp"
71             // Used to hide any of the table of contents nested items
72             hideEffect: "slideUp",
73
74             // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
75             // The time duration of the hide animation
76             hideEffectSpeed: "medium",
77
78             // **smoothScroll**: Accepts a boolean: true or false
79             // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page
80             smoothScroll: true,
81
82             // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast"
83             // The time duration of the smoothScroll animation
84             smoothScrollSpeed: "medium",
85
86             // **scrollTo**: Accepts Number (pixels)
87             // The amount of space between the top of page and the selected table of contents item after the page has been scrolled
88             scrollTo: 0,
89
90             // **showAndHideOnScroll**: Accepts a boolean: true or false
91             // Determines if table of contents nested items should be shown and hidden while scrolling
92             showAndHideOnScroll: true,
93
94             // **highlightOnScroll**: Accepts a boolean: true or false
95             // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling
96             highlightOnScroll: true,
97
98             // **highlightOffset**: Accepts a number
99             // The offset distance in pixels to trigger the next active table of contents item
100             highlightOffset: 40,
101
102             // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none"
103             // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents
104             theme: "bootstrap",
105
106             // **extendPage**: Accepts a boolean: true or false
107             // 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
108             extendPage: true,
109
110             // **extendPageOffset**: Accepts a number: pixels
111             // How close to the bottom of the page a user must scroll before the page is extended
112             extendPageOffset: 100,
113
114             // **history**: Accepts a boolean: true or false
115             // Adds a hash to the page url to maintain history
116             history: true,
117
118             // **scrollHistory**: Accepts a boolean: true or false
119             // Adds a hash to the page url, to maintain history, when scrolling to a TOC item
120             scrollHistory: false,
121
122             // **hashGenerator**: How the hash value (the anchor segment of the URL, following the
123             // # character) will be generated.
124             //
125             // "compact" (default) - #CompressesEverythingTogether
126             // "pretty" - #looks-like-a-nice-url-and-is-easily-readable
127             // function(text, element){} - Your own hash generation function that accepts the text as an
128             // argument, and returns the hash value.
129             hashGenerator: "compact",
130
131             // **highlightDefault**: Accepts a boolean: true or false
132             // Set's the first TOC item as active if no other TOC item is active.
133             highlightDefault: true
134
135         },
136
137         // _Create
138         // -------
139         //      Constructs the plugin.  Only called once.
140         _create: function() {
141
142             var self = this;
143
144             self.extendPageScroll = true;
145
146             // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings)
147             self.items = [];
148
149             // Generates the HTML for the dynamic table of contents
150             self._generateToc();
151
152             // Adds CSS classes to the newly generated table of contents HTML
153             self._addCSSClasses();
154
155             self.webkit = (function() {
156
157                 for(var prop in window) {
158
159                     if(prop) {
160
161                         if(prop.toLowerCase().indexOf("webkit") !== -1) {
162
163                             return true;
164
165                         }
166
167                     }
168
169                 }
170
171                 return false;
172
173             }());
174
175             // Adds jQuery event handlers to the newly generated table of contents
176             self._setEventHandlers();
177
178             // Binding to the Window load event to make sure the correct scrollTop is calculated
179             $(window).load(function() {
180
181                 // Sets the active TOC item
182                 self._setActiveElement(true);
183
184                 // Once all animations on the page are complete, this callback function will be called
185                 $("html, body").promise().done(function() {
186
187                     setTimeout(function() {
188
189                         self.extendPageScroll = false;
190
191                     },0);
192
193                 });
194
195             });
196
197         },
198
199         // _generateToc
200         // ------------
201         //      Generates the HTML for the dynamic table of contents
202         _generateToc: function() {
203
204             // _Local variables_
205
206             // Stores the plugin context in the self variable
207             var self = this,
208
209                 // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above
210                 firstElem,
211
212                 // Instantiated variable that will store the top level newly created unordered list DOM element
213                 ul,
214                 ignoreSelector = self.options.ignoreSelector;
215
216              // If the selectors option has a comma within the string
217              if(this.options.selectors.indexOf(",") !== -1) {
218
219                  // Grabs the first selector from the string
220                  firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(",")));
221
222              }
223
224              // If the selectors option does not have a comman within the string
225              else {
226
227                  // Grabs the first selector from the string and makes sure there are no spaces
228                  firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,""));
229
230              }
231
232             if(!firstElem.length) {
233
234                 self.element.addClass(hideTocClassName);
235
236                 return;
237
238             }
239
240             self.element.addClass(tocClassName);
241
242             // Loops through each top level selector
243             firstElem.each(function(index) {
244
245                 //If the element matches the ignoreSelector then we skip it
246                 if($(this).is(ignoreSelector)) {
247                     return;
248                 }
249
250                 // Creates an unordered list HTML element and adds a dynamic ID and standard class name
251                 ul = $("<ul/>", {
252                     "id": headerClassName + index,
253                     "class": headerClassName
254                 }).
255
256                 // Appends a top level list item HTML element to the previously created HTML header
257                 append(self._nestElements($(this), index));
258
259                 // Add the created unordered list element to the HTML element calling the plugin
260                 self.element.append(ul);
261
262                 // Finds all of the HTML tags between the header and subheader elements
263                 $(this).nextUntil(this.nodeName.toLowerCase()).each(function() {
264
265                     // If there are no nested subheader elemements
266                     if($(this).find(self.options.selectors).length === 0) {
267
268                         // Loops through all of the subheader elements
269                         $(this).filter(self.options.selectors).each(function() {
270
271                             //If the element matches the ignoreSelector then we skip it
272                             if($(this).is(ignoreSelector)) {
273                                 return;
274                             }
275
276                             self._appendSubheaders.call(this, self, ul);
277
278                         });
279
280                     }
281
282                     // If there are nested subheader elements
283                     else {
284
285                         // Loops through all of the subheader elements
286                         $(this).find(self.options.selectors).each(function() {
287
288                             //If the element matches the ignoreSelector then we skip it
289                             if($(this).is(ignoreSelector)) {
290                                 return;
291                             }
292
293                             self._appendSubheaders.call(this, self, ul);
294
295                         });
296
297                     }
298
299                 });
300
301             });
302
303         },
304
305         _setActiveElement: function(pageload) {
306
307             var self = this,
308
309                 hash = window.location.hash.substring(1),
310
311                 elem = self.element.find('li[data-unique="' + hash + '"]');
312
313             if(hash.length) {
314
315                 // Removes highlighting from all of the list item's
316                 self.element.find("." + self.focusClass).removeClass(self.focusClass);
317
318                 // Highlights the current list item that was clicked
319                 elem.addClass(self.focusClass);
320
321                 // If the showAndHide option is true
322                 if(self.options.showAndHide) {
323
324                     // Triggers the click event on the currently focused TOC item
325                     elem.click();
326
327                 }
328
329             }
330
331             else {
332
333                 // Removes highlighting from all of the list item's
334                 self.element.find("." + self.focusClass).removeClass(self.focusClass);
335
336                 if(!hash.length && pageload && self.options.highlightDefault) {
337
338                     // Highlights the first TOC item if no other items are highlighted
339                     self.element.find(itemClass).first().addClass(self.focusClass);
340
341                 }
342
343             }
344
345             return self;
346
347         },
348
349         // _nestElements
350         // -------------
351         //      Helps create the table of contents list by appending nested list items
352         _nestElements: function(self, index) {
353
354             var arr, item, hashValue;
355
356             arr = $.grep(this.items, function (item) {
357
358                 return item === self.text();
359
360             });
361
362             // If there is already a duplicate TOC item
363             if(arr.length) {
364
365                 // Adds the current TOC item text and index (for slight randomization) to the internal array
366                 this.items.push(self.text() + index);
367
368             }
369
370             // If there not a duplicate TOC item
371             else {
372
373                 // Adds the current TOC item text to the internal array
374                 this.items.push(self.text());
375
376             }
377
378             hashValue = this._generateHashValue(arr, self, index);
379
380             // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
381             item = $("<li/>", {
382
383                 // Sets a common class name to the list item
384                 "class": itemClassName,
385
386                 "data-unique": hashValue
387
388             }).append($("<a/>", {
389
390                 "text": self.text()
391
392             }));
393
394             // Adds an HTML anchor tag before the currently traversed HTML element
395             self.before($("<div/>", {
396
397                 // 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)
398                 "name": hashValue,
399
400                 "data-unique": hashValue
401
402             }));
403
404             return item;
405
406         },
407
408         // _generateHashValue
409         // ------------------
410         //      Generates the hash value that will be used to refer to each item.
411         _generateHashValue: function(arr, self, index) {
412
413             var hashValue = "",
414                 hashGeneratorOption = this.options.hashGenerator;
415
416             if (hashGeneratorOption === "pretty") {
417
418                 // prettify the text
419                 hashValue = self.text().toLowerCase().replace(/\s/g, "-");
420
421                 // fix double hyphens
422                 while (hashValue.indexOf("--") > -1) {
423                     hashValue = hashValue.replace(/--/g, "-");
424                 }
425
426                 // fix colon-space instances
427                 while (hashValue.indexOf(":-") > -1) {
428                     hashValue = hashValue.replace(/:-/g, "-");
429                 }
430
431             } else if (typeof hashGeneratorOption === "function") {
432
433                 // call the function
434                 hashValue = hashGeneratorOption(self.text(), self);
435
436             } else {
437
438                 // compact - the default
439                 hashValue = self.text().replace(/\s/g, "");
440
441             }
442
443             // add the index if we need to
444             if (arr.length) { hashValue += ""+index; }
445
446             // return the value
447             return hashValue;
448
449         },
450
451         // _appendElements
452         // ---------------
453         //      Helps create the table of contents list by appending subheader elements
454
455         _appendSubheaders: function(self, ul) {
456
457             // The current element index
458             var index = $(this).index(self.options.selectors),
459
460                 // Finds the previous header DOM element
461                 previousHeader = $(self.options.selectors).eq(index - 1),
462
463                 currentTagName = +$(this).prop("tagName").charAt(1),
464
465                 previousTagName = +previousHeader.prop("tagName").charAt(1),
466
467                 lastSubheader;
468
469             // If the current header DOM element is smaller than the previous header DOM element or the first subheader
470             if(currentTagName < previousTagName) {
471
472                 // Selects the last unordered list HTML found within the HTML element calling the plugin
473                 self.element.find(subheaderClass + "[data-tag=" + currentTagName + "]").last().append(self._nestElements($(this), index));
474
475             }
476
477             // If the current header DOM element is the same type of header(eg. h4) as the previous header DOM element
478             else if(currentTagName === previousTagName) {
479
480                 ul.find(itemClass).last().after(self._nestElements($(this), index));
481
482             }
483
484             else {
485
486                 // Selects the last unordered list HTML found within the HTML element calling the plugin
487                 ul.find(itemClass).last().
488
489                 // Appends an unorderedList HTML element to the dynamic `unorderedList` variable and sets a common class name
490                 after($("<ul/>", {
491
492                     "class": subheaderClassName,
493
494                     "data-tag": currentTagName
495
496                 })).next(subheaderClass).
497
498                 // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin
499                 append(self._nestElements($(this), index));
500             }
501
502         },
503
504        // _setEventHandlers
505         // ----------------
506         //      Adds jQuery event handlers to the newly generated table of contents
507         _setEventHandlers: function() {
508
509             // _Local variables_
510
511             // Stores the plugin context in the self variable
512             var self = this,
513
514                 // Instantiates a new variable that will be used to hold a specific element's context
515                 $self,
516
517                 // Instantiates a new variable that will be used to determine the smoothScroll animation time duration
518                 duration;
519
520             // Event delegation that looks for any clicks on list item elements inside of the HTML element calling the plugin
521             this.element.on("click.tocify", "li", function(event) {
522
523                 if(self.options.history) {
524
525                     window.location.hash = $(this).attr("data-unique");
526
527                 }
528
529                 // Removes highlighting from all of the list item's
530                 self.element.find("." + self.focusClass).removeClass(self.focusClass);
531
532                 // Highlights the current list item that was clicked
533                 $(this).addClass(self.focusClass);
534
535                 // If the showAndHide option is true
536                 if(self.options.showAndHide) {
537
538                     var elem = $('li[data-unique="' + $(this).attr("data-unique") + '"]');
539
540                     self._triggerShow(elem);
541
542                 }
543
544                 self._scrollTo($(this));
545
546             });
547
548             // Mouseenter and Mouseleave event handlers for the list item's within the HTML element calling the plugin
549             this.element.find("li").on({
550
551                 // Mouseenter event handler
552                 "mouseenter.tocify": function() {
553
554                     // Adds a hover CSS class to the current list item
555                     $(this).addClass(self.hoverClass);
556
557                     // Makes sure the cursor is set to the pointer icon
558                     $(this).css("cursor", "pointer");
559
560                 },
561
562                 // Mouseleave event handler
563                 "mouseleave.tocify": function() {
564
565                     if(self.options.theme !== "bootstrap") {
566
567                         // Removes the hover CSS class from the current list item
568                         $(this).removeClass(self.hoverClass);
569
570                     }
571
572                 }
573             });
574
575             // only attach handler if needed (expensive in IE)
576             if (self.options.extendPage || self.options.highlightOnScroll || self.options.scrollHistory || self.options.showAndHideOnScroll)
577             {
578             // Window scroll event handler
579                 $(window).on("scroll.tocify", function() {
580
581                     // Once all animations on the page are complete, this callback function will be called
582                     $("html, body").promise().done(function() {
583
584                         // Local variables
585
586                         // Stores how far the user has scrolled
587                         var winScrollTop = $(window).scrollTop(),
588
589                             // Stores the height of the window
590                             winHeight = $(window).height(),
591
592                             // Stores the height of the document
593                             docHeight = $(document).height(),
594
595                             scrollHeight = $("body")[0].scrollHeight,
596
597                             // Instantiates a variable that will be used to hold a selected HTML element
598                             elem,
599
600                             lastElem,
601
602                             lastElemOffset,
603
604                             currentElem;
605
606                         if(self.options.extendPage) {
607
608                             // If the user has scrolled to the bottom of the page and the last toc item is not focused
609                             if((self.webkit && winScrollTop >= scrollHeight - winHeight - self.options.extendPageOffset) || (!self.webkit && winHeight + winScrollTop > docHeight - self.options.extendPageOffset)) {
610
611                                 if(!$(extendPageClass).length) {
612
613                                     lastElem = $('div[data-unique="' + $(itemClass).last().attr("data-unique") + '"]');
614
615                                     if(!lastElem.length) return;
616
617                                     // Gets the top offset of the page header that is linked to the last toc item
618                                     lastElemOffset = lastElem.offset().top;
619
620                                     // 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
621                                     $(self.options.context).append($("<div />", {
622
623                                         "class": extendPageClassName,
624
625                                         "height": Math.abs(lastElemOffset - winScrollTop) + "px",
626
627                                         "data-unique": extendPageClassName
628
629                                     }));
630
631                                     if(self.extendPageScroll) {
632
633                                         currentElem = self.element.find('li.active');
634
635                                         self._scrollTo($('div[data-unique="' + currentElem.attr("data-unique") + '"]'));
636
637                                     }
638
639                                 }
640
641                             }
642
643                         }
644
645                         // The zero timeout ensures the following code is run after the scroll events
646                         setTimeout(function() {
647
648                             // _Local variables_
649
650                             // Stores the distance to the closest anchor
651                             var closestAnchorDistance = null,
652
653                                 // Stores the index of the closest anchor
654                                 closestAnchorIdx = null,
655
656                                 // Keeps a reference to all anchors
657                                 anchors = $(self.options.context).find("div[data-unique]"),
658
659                                 anchorText;
660
661                             // Determines the index of the closest anchor
662                             anchors.each(function(idx) {
663                                 var distance = Math.abs(($(this).next().length ? $(this).next() : $(this)).offset().top - winScrollTop - self.options.highlightOffset);
664                                 if (closestAnchorDistance == null || distance < closestAnchorDistance) {
665                                     closestAnchorDistance = distance;
666                                     closestAnchorIdx = idx;
667                                 } else {
668                                     return false;
669                                 }
670                             });
671
672                             anchorText = $(anchors[closestAnchorIdx]).attr("data-unique");
673
674                             // Stores the list item HTML element that corresponds to the currently traversed anchor tag
675                             elem = $('li[data-unique="' + anchorText + '"]');
676
677                             // If the `highlightOnScroll` option is true and a next element is found
678                             if(self.options.highlightOnScroll && elem.length) {
679
680                                 // Removes highlighting from all of the list item's
681                                 self.element.find("." + self.focusClass).removeClass(self.focusClass);
682
683                                 // Highlights the corresponding list item
684                                 elem.addClass(self.focusClass);
685
686                             }
687
688                             if(self.options.scrollHistory) {
689
690                                 if(window.location.hash !== "#" + anchorText) {
691
692                                     window.location.replace("#" + anchorText);
693
694                                 }
695                             }
696
697                             // If the `showAndHideOnScroll` option is true
698                             if(self.options.showAndHideOnScroll && self.options.showAndHide) {
699
700                                 self._triggerShow(elem, true);
701
702                             }
703
704                         }, 0);
705
706                     });
707
708                 });
709             }
710
711         },
712
713         // Show
714         // ----
715         //      Opens the current sub-header
716         show: function(elem, scroll) {
717
718             // Stores the plugin context in the `self` variable
719             var self = this,
720                 element = elem;
721
722             // If the sub-header is not already visible
723             if (!elem.is(":visible")) {
724
725                 // If the current element does not have any nested subheaders, is not a header, and its parent is not visible
726                 if(!elem.find(subheaderClass).length && !elem.parent().is(headerClass) && !elem.parent().is(":visible")) {
727
728                     // Sets the current element to all of the subheaders within the current header
729                     elem = elem.parents(subheaderClass).add(elem);
730
731                 }
732
733                 // If the current element does not have any nested subheaders and is not a header
734                 else if(!elem.children(subheaderClass).length && !elem.parent().is(headerClass)) {
735
736                     // Sets the current element to the closest subheader
737                     elem = elem.closest(subheaderClass);
738
739                 }
740
741                 //Determines what jQuery effect to use
742                 switch (self.options.showEffect) {
743
744                     //Uses `no effect`
745                     case "none":
746
747                         elem.show();
748
749                     break;
750
751                     //Uses the jQuery `show` special effect
752                     case "show":
753
754                         elem.show(self.options.showEffectSpeed);
755
756                     break;
757
758                     //Uses the jQuery `slideDown` special effect
759                     case "slideDown":
760
761                         elem.slideDown(self.options.showEffectSpeed);
762
763                     break;
764
765                     //Uses the jQuery `fadeIn` special effect
766                     case "fadeIn":
767
768                         elem.fadeIn(self.options.showEffectSpeed);
769
770                     break;
771
772                     //If none of the above options were passed, then a `jQueryUI show effect` is expected
773                     default:
774
775                         elem.show();
776
777                     break;
778
779                 }
780
781             }
782
783             // If the current subheader parent element is a header
784             if(elem.parent().is(headerClass)) {
785
786                 // Hides all non-active sub-headers
787                 self.hide($(subheaderClass).not(elem));
788
789             }
790
791             // If the current subheader parent element is not a header
792             else {
793
794                 // Hides all non-active sub-headers
795                 self.hide($(subheaderClass).not(elem.closest(headerClass).find(subheaderClass).not(elem.siblings())));
796
797             }
798
799             // Maintains chainablity
800             return self;
801
802         },
803
804         // Hide
805         // ----
806         //      Closes the current sub-header
807         hide: function(elem) {
808
809             // Stores the plugin context in the `self` variable
810             var self = this;
811
812             //Determines what jQuery effect to use
813             switch (self.options.hideEffect) {
814
815                 // Uses `no effect`
816                 case "none":
817
818                     elem.hide();
819
820                 break;
821
822                 // Uses the jQuery `hide` special effect
823                 case "hide":
824
825                     elem.hide(self.options.hideEffectSpeed);
826
827                 break;
828
829                 // Uses the jQuery `slideUp` special effect
830                 case "slideUp":
831
832                     elem.slideUp(self.options.hideEffectSpeed);
833
834                 break;
835
836                 // Uses the jQuery `fadeOut` special effect
837                 case "fadeOut":
838
839                     elem.fadeOut(self.options.hideEffectSpeed);
840
841                 break;
842
843                 // If none of the above options were passed, then a `jqueryUI hide effect` is expected
844                 default:
845
846                     elem.hide();
847
848                 break;
849
850             }
851
852             // Maintains chainablity
853             return self;
854         },
855
856         // _triggerShow
857         // ------------
858         //      Determines what elements get shown on scroll and click
859         _triggerShow: function(elem, scroll) {
860
861             var self = this;
862
863             // If the current element's parent is a header element or the next element is a nested subheader element
864             if(elem.parent().is(headerClass) || elem.next().is(subheaderClass)) {
865
866                 // Shows the next sub-header element
867                 self.show(elem.next(subheaderClass), scroll);
868
869             }
870
871             // If the current element's parent is a subheader element
872             else if(elem.parent().is(subheaderClass)) {
873
874                 // Shows the parent sub-header element
875                 self.show(elem.parent(), scroll);
876
877             }
878
879             // Maintains chainability
880             return self;
881
882         },
883
884         // _addCSSClasses
885         // --------------
886         //      Adds CSS classes to the newly generated table of contents HTML
887         _addCSSClasses: function() {
888
889             // If the user wants a jqueryUI theme
890             if(this.options.theme === "jqueryui") {
891
892                 this.focusClass = "ui-state-default";
893
894                 this.hoverClass = "ui-state-hover";
895
896                 //Adds the default styling to the dropdown list
897                 this.element.addClass("ui-widget").find(".toc-title").addClass("ui-widget-header").end().find("li").addClass("ui-widget-content");
898
899             }
900
901             // If the user wants a twitterBootstrap theme
902             else if(this.options.theme === "bootstrap") {
903
904                 this.element.find(headerClass + "," + subheaderClass).addClass("nav nav-list");
905
906                 this.focusClass = "active";
907
908             }
909
910             // If a user does not want a prebuilt theme
911             else {
912
913                 // Adds more neutral classes (instead of jqueryui)
914
915                 this.focusClass = tocFocusClassName;
916
917                 this.hoverClass = tocHoverClassName;
918
919             }
920
921             //Maintains chainability
922             return this;
923
924         },
925
926         // setOption
927         // ---------
928         //      Sets a single Tocify option after the plugin is invoked
929         setOption: function() {
930
931             // Calls the jQueryUI Widget Factory setOption method
932             $.Widget.prototype._setOption.apply(this, arguments);
933
934         },
935
936         // setOptions
937         // ----------
938         //      Sets a single or multiple Tocify options after the plugin is invoked
939         setOptions: function() {
940
941             // Calls the jQueryUI Widget Factory setOptions method
942             $.Widget.prototype._setOptions.apply(this, arguments);
943
944         },
945
946         // _scrollTo
947         // ---------
948         //      Scrolls to a specific element
949         _scrollTo: function(elem) {
950
951             var self = this,
952                 duration = self.options.smoothScroll || 0,
953                 scrollTo = self.options.scrollTo,
954                 currentDiv = $('div[data-unique="' + elem.attr("data-unique") + '"]');
955
956             if(!currentDiv.length) {
957
958                 return self;
959
960             }
961
962             // Once all animations on the page are complete, this callback function will be called
963             $("html, body").promise().done(function() {
964
965                 // Animates the html and body element scrolltops
966                 $("html, body").animate({
967
968                     // Sets the jQuery `scrollTop` to the top offset of the HTML div tag that matches the current list item's `data-unique` tag
969                     "scrollTop": currentDiv.offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + "px"
970
971                 }, {
972
973                     // Sets the smoothScroll animation time duration to the smoothScrollSpeed option
974                     "duration": duration
975
976                 });
977
978             });
979
980             // Maintains chainability
981             return self;
982
983         }
984
985     });
986
987 })); //end of plugin