• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1(function() {
2  var SOURCES = window.TEXT_VARIABLES.sources;
3  window.Lazyload.js(SOURCES.jquery, function() {
4    function toc(options) {
5      var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
6        selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
7        headingsPos, scrolling = false, hasRendered = false, hasInit = false;
8
9      function setOptions(options) {
10        var _options = options || {};
11        _options.selectors && (selectors = _options.selectors);
12        _options.container && (container = _options.container);
13        _options.scrollTarget && (scrollTarget = _options.scrollTarget);
14        _options.scroller && (scroller = _options.scroller);
15        _options.disabled !== undefined && (disabled = _options.disabled);
16        $headings = $(container).find(selectors).filter('[id]');
17        $scrollTarget = $(scrollTarget);
18        $scroller = $(scroller);
19      }
20      function calc() {
21        headingsPos = [];
22        $headings.each(function() {
23          headingsPos.push(Math.floor($(this).position().top));
24        });
25      }
26      function setState(element, disabled) {
27        var scrollTop = $scrollTarget.scrollTop(), i;
28        if (disabled || !headingsPos || headingsPos.length < 1) { return; }
29        if (element) {
30          $activeCur = element;
31        } else {
32          for (i = 0; i < headingsPos.length; i++) {
33            if (scrollTop >= headingsPos[i]) {
34              $activeCur = $tocLi.eq(i);
35            } else {
36              $activeCur || ($activeCur = $tocLi.eq(i));
37              break;
38            }
39          }
40        }
41        $activeLast && $activeLast.removeClass('active');
42        ($activeLast = $activeCur).addClass('active');
43      }
44      function render() {
45        if(!hasRendered) {
46          $root.append($tocUl);
47          $headings.each(function() {
48            var $this = $(this);
49            $tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
50              .append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
51          });
52          $tocLi = $tocUl.children('li');
53          $tocUl.on('click', 'a', function(e) {
54            e.preventDefault();
55            var $this = $(this);
56            scrolling = true;
57            setState($this.parent());
58            $scroller.scrollToAnchor($this.attr('href'), 400, function() {
59              scrolling = false;
60            });
61          });
62        }
63        hasRendered = true;
64      }
65      function init() {
66        var interval, timeout;
67        if(!hasInit) {
68          render(); calc(); setState(null, scrolling);
69          // run calc every 100 millisecond
70          interval = setInterval(function() {
71            calc();
72          }, 100);
73          timeout = setTimeout(function() {
74            clearInterval(interval);
75          }, 45000);
76          window.pageLoad.then(function() {
77            setTimeout(function() {
78              clearInterval(interval);
79              clearTimeout(timeout);
80            }, 3000);
81          });
82          $scrollTarget.on('scroll', function() {
83            disabled || setState(null, scrolling);
84          });
85          $window.on('resize', window.throttle(function() {
86            if (!disabled) {
87              render(); calc(); setState(null, scrolling);
88            }
89          }, 100));
90        }
91        hasInit = true;
92      }
93
94      setOptions(options);
95      if (!disabled) {
96        init();
97      }
98      $window.on('resize', window.throttle(function() {
99        init();
100      }, 200));
101      return {
102        setOptions: setOptions
103      };
104    }
105    $.fn.toc = toc;
106  });
107})();