|
1 | 1 | /* jquery Tocify - v1.8.0 - 2013-09-16 |
2 | 2 | * http://www.gregfranko.com/jquery.tocify.js/ |
3 | | -* Copyright (c) 2013 Greg Franko; Licensed MIT */ |
| 3 | +* Copyright (c) 2013 Greg Franko; Licensed MIT |
| 4 | +* Modified lightly by Robert Lord to fix a bug I found, |
| 5 | +* and also so it adds ids to headers |
| 6 | +* also because I want height caching, since the |
| 7 | +* height lookup for h1s and h2s was causing serious |
| 8 | +* lag spikes below 30 fps */ |
4 | 9 |
|
5 | 10 | // 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 | 11 | (function(tocify) { |
|
149 | 154 | // Generates the HTML for the dynamic table of contents |
150 | 155 | self._generateToc(); |
151 | 156 |
|
| 157 | + // Caches heights and anchors |
| 158 | + self.cachedHeights = [], |
| 159 | + self.cachedAnchors = []; |
| 160 | + |
152 | 161 | // Adds CSS classes to the newly generated table of contents HTML |
153 | 162 | self._addCSSClasses(); |
154 | 163 |
|
|
377 | 386 |
|
378 | 387 | hashValue = this._generateHashValue(arr, self, index); |
379 | 388 |
|
| 389 | + // ADDED BY ROBERT |
| 390 | + // actually add the hash value to the element's id |
| 391 | + self.attr("id", "link-" + hashValue); |
| 392 | + |
380 | 393 | // Appends a list item HTML element to the last unordered list HTML element found within the HTML element calling the plugin |
381 | 394 | item = $("<li/>", { |
382 | 395 |
|
|
414 | 427 | hashGeneratorOption = this.options.hashGenerator; |
415 | 428 |
|
416 | 429 | if (hashGeneratorOption === "pretty") { |
| 430 | + // remove weird characters |
| 431 | + |
417 | 432 |
|
418 | 433 | // prettify the text |
419 | 434 | hashValue = self.text().toLowerCase().replace(/\s/g, "-"); |
420 | 435 |
|
| 436 | + // ADDED BY ROBERT |
| 437 | + // remove weird characters |
| 438 | + hashValue = hashValue.replace(/[^\x00-\x7F]/g, ""); |
| 439 | + |
421 | 440 | // fix double hyphens |
422 | 441 | while (hashValue.indexOf("--") > -1) { |
423 | 442 | hashValue = hashValue.replace(/--/g, "-"); |
|
645 | 664 | // _Local variables_ |
646 | 665 |
|
647 | 666 | // Stores the distance to the closest anchor |
648 | | - var closestAnchorDistance = null, |
649 | | - |
650 | | - // Stores the index of the closest anchor |
| 667 | + var // Stores the index of the closest anchor |
651 | 668 | closestAnchorIdx = null, |
652 | | - |
653 | | - // Keeps a reference to all anchors |
654 | | - anchors = $(self.options.context).find("div[data-unique]"), |
655 | | - |
656 | 669 | anchorText; |
657 | 670 |
|
| 671 | + self.calculateHeights(); |
| 672 | + |
658 | 673 | // Determines the index of the closest anchor |
659 | | - anchors.each(function(idx) { |
660 | | - var distance = /*Math.abs*/(($(this).next().length ? $(this).next() : $(this)).offset().top - winScrollTop - self.options.highlightOffset); |
661 | | - if (distance < 0) { |
662 | | - closestAnchorDistance = distance; |
| 674 | + self.cachedAnchors.each(function(idx) { |
| 675 | + if (self.cachedHeights[idx] - $(window).scrollTop() < 0) { |
663 | 676 | closestAnchorIdx = idx; |
664 | 677 | } else { |
665 | 678 | return false; |
666 | 679 | } |
667 | 680 | }); |
668 | 681 |
|
669 | | - anchorText = $(anchors[closestAnchorIdx]).attr("data-unique"); |
| 682 | + anchorText = $(self.cachedAnchors[closestAnchorIdx]).attr("data-unique"); |
670 | 683 |
|
671 | 684 | // Stores the list item HTML element that corresponds to the currently traversed anchor tag |
672 | 685 | elem = $('li[data-unique="' + anchorText + '"]'); |
|
684 | 697 |
|
685 | 698 | if(self.options.scrollHistory) { |
686 | 699 |
|
687 | | - if(window.location.hash !== anchorText) { |
| 700 | + if(window.location.hash !== "#" + anchorText) { |
688 | 701 |
|
689 | | - window.location.hash = anchorText; |
| 702 | + window.location.replace("#" + anchorText); |
690 | 703 |
|
691 | 704 | } |
692 | 705 |
|
|
707 | 720 |
|
708 | 721 | }, |
709 | 722 |
|
| 723 | + // calculateHeights |
| 724 | + // ---- |
| 725 | + // ADDED BY ROBERT |
| 726 | + calculateHeights: function() { |
| 727 | + var self = this; |
| 728 | + if (self.cachedHeights.length == 0) { |
| 729 | + self.cachedHeights = []; |
| 730 | + self.cachedAnchors = []; |
| 731 | + var anchors = $(self.options.context).find("div[data-unique]"); |
| 732 | + anchors.each(function(idx) { |
| 733 | + var distance = (($(this).next().length ? $(this).next() : $(this)).offset().top - self.options.highlightOffset); |
| 734 | + self.cachedHeights[idx] = distance; |
| 735 | + }); |
| 736 | + self.cachedAnchors = anchors; |
| 737 | + } |
| 738 | + }, |
| 739 | + |
710 | 740 | // Show |
711 | 741 | // ---- |
712 | 742 | // Opens the current sub-header |
|
956 | 986 | $("html, body").animate({ |
957 | 987 |
|
958 | 988 | // Sets the jQuery `scrollTop` to the top offset of the HTML div tag that matches the current list item's `data-unique` tag |
959 | | - "scrollTop": $('div[data-unique="' + elem.attr("data-unique") + '"]').offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + "px" |
| 989 | + "scrollTop": $('div[data-unique="' + elem.attr("data-unique") + '"]').next().offset().top - ($.isFunction(scrollTo) ? scrollTo.call() : scrollTo) + "px" |
960 | 990 |
|
961 | 991 | }, { |
962 | 992 |
|
|
0 commit comments