1 | !function($) {
|
---|
2 | $.fn.toc = function(options) {
|
---|
3 | var self = this;
|
---|
4 | var opts = $.extend({}, jQuery.fn.toc.defaults, options);
|
---|
5 |
|
---|
6 | var container = $(opts.container);
|
---|
7 | var headings = $(opts.selectors, container);
|
---|
8 | var headingOffsets = [];
|
---|
9 | var activeClassName = opts.prefix+'-active';
|
---|
10 |
|
---|
11 | var findScrollableElement = function(els) {
|
---|
12 | for (var i = 0, argLength = arguments.length; i < argLength; i++) {
|
---|
13 | var el = arguments[i],
|
---|
14 | $scrollElement = $(el);
|
---|
15 | if ($scrollElement.scrollTop() > 0) {
|
---|
16 | return $scrollElement;
|
---|
17 | } else {
|
---|
18 | $scrollElement.scrollTop(1);
|
---|
19 | var isScrollable = $scrollElement.scrollTop() > 0;
|
---|
20 | $scrollElement.scrollTop(0);
|
---|
21 | if (isScrollable) {
|
---|
22 | return $scrollElement;
|
---|
23 | }
|
---|
24 | }
|
---|
25 | }
|
---|
26 | return [];
|
---|
27 | };
|
---|
28 | var scrollable = findScrollableElement(opts.container, 'body', 'html');
|
---|
29 |
|
---|
30 | var scrollTo = function(e) {
|
---|
31 | if (opts.smoothScrolling) {
|
---|
32 | e.preventDefault();
|
---|
33 | var elScrollTo = $(e.target).attr('href');
|
---|
34 | var $el = $(elScrollTo);
|
---|
35 |
|
---|
36 | scrollable.animate({ scrollTop: $el.offset().top }, 400, 'swing', function() {
|
---|
37 | location.hash = elScrollTo;
|
---|
38 | });
|
---|
39 | }
|
---|
40 | $('li', self).removeClass(activeClassName);
|
---|
41 | $(e.target).parent().addClass(activeClassName);
|
---|
42 | };
|
---|
43 |
|
---|
44 | //highlight on scroll
|
---|
45 | var timeout;
|
---|
46 | var highlightOnScroll = function(e) {
|
---|
47 | if (timeout) {
|
---|
48 | clearTimeout(timeout);
|
---|
49 | }
|
---|
50 | timeout = setTimeout(function() {
|
---|
51 | var top = $(window).scrollTop();
|
---|
52 | for (var i = 0, c = headingOffsets.length; i < c; i++) {
|
---|
53 | if (headingOffsets[i] >= top) {
|
---|
54 | $('li', self).removeClass(activeClassName);
|
---|
55 | $('li:eq('+(i-1)+')', self).addClass(activeClassName);
|
---|
56 | break;
|
---|
57 | }
|
---|
58 | }
|
---|
59 | }, 50);
|
---|
60 | };
|
---|
61 | if (opts.highlightOnScroll) {
|
---|
62 | $(window).bind('scroll', highlightOnScroll);
|
---|
63 | highlightOnScroll();
|
---|
64 | }
|
---|
65 |
|
---|
66 | return this.each(function() {
|
---|
67 | //build TOC
|
---|
68 | var ul = $('<ul/>');
|
---|
69 | headings.each(function(i, heading) {
|
---|
70 | var $h = $(heading);
|
---|
71 | headingOffsets.push($h.offset().top - opts.highlightOffset);
|
---|
72 |
|
---|
73 | //add anchor
|
---|
74 | var anchorName = opts.anchorName(i, heading, opts.prefix);
|
---|
75 | var anchor = $([]);
|
---|
76 | if (!document.getElementById(anchorName)) {
|
---|
77 | anchor = $('<span/>').attr('id', opts.anchorName(i, heading, opts.prefix)).insertBefore($h);
|
---|
78 | }
|
---|
79 | //build TOC item
|
---|
80 | var a = $('<a/>')
|
---|
81 | .text($h.text())
|
---|
82 | .attr('href', '#' + anchorName)
|
---|
83 | .bind('click', scrollTo);
|
---|
84 |
|
---|
85 | var li = $('<li/>')
|
---|
86 | .addClass(opts.prefix+'-'+$h[0].tagName.toLowerCase())
|
---|
87 | .append(a);
|
---|
88 |
|
---|
89 | ul.append(li);
|
---|
90 | });
|
---|
91 | var el = $(this);
|
---|
92 | el.html(ul);
|
---|
93 | });
|
---|
94 | };
|
---|
95 |
|
---|
96 |
|
---|
97 | jQuery.fn.toc.defaults = {
|
---|
98 | container: 'body',
|
---|
99 | selectors: 'h1,h2,h3',
|
---|
100 | smoothScrolling: true,
|
---|
101 | prefix: '',
|
---|
102 | highlightOnScroll: true,
|
---|
103 | highlightOffset: 100,
|
---|
104 | anchorName: function(i, heading, prefix) {
|
---|
105 | return prefix+i;
|
---|
106 | }
|
---|
107 | };
|
---|
108 |
|
---|
109 | }(jQuery); |
---|