1/** 2 * Single Page Nav Plugin 3 * Copyright (c) 2014 Chris Wojcik <[email protected]> 4 * Dual licensed under MIT and GPL. 5 * @author Chris Wojcik 6 * @version 1.2.0 7 */ 8 9// Utility 10if (typeof Object.create !== "function") { 11 Object.create = function (obj) { 12 function F() {} 13 F.prototype = obj; 14 return new F(); 15 }; 16} 17 18(function ($, window, document, undefined) { 19 "use strict"; 20 21 var SinglePageNav = { 22 init: function (options, container) { 23 this.options = $.extend({}, $.fn.singlePageNav.defaults, options); 24 25 this.container = container; 26 this.$container = $(container); 27 this.$links = this.$container.find("a"); 28 29 if (this.options.filter !== "") { 30 this.$links = this.$links.filter(this.options.filter); 31 } 32 33 this.$window = $(window); 34 this.$htmlbody = $("html, body"); 35 36 this.$links.on("click.singlePageNav", $.proxy(this.handleClick, this)); 37 38 this.didScroll = false; 39 this.checkPosition(); 40 this.setTimer(); 41 }, 42 43 handleClick: function (e) { 44 var self = this, 45 link = e.currentTarget, 46 $elem = $(link.hash); 47 48 e.preventDefault(); 49 50 if ($elem.length) { 51 // Make sure the target elem exists 52 53 // Prevent active link from cycling during the scroll 54 self.clearTimer(); 55 56 // Before scrolling starts 57 if (typeof self.options.beforeStart === "function") { 58 self.options.beforeStart(); 59 } 60 61 self.setActiveLink(link.hash); 62 63 self.scrollTo($elem, function () { 64 if (self.options.updateHash && history.pushState) { 65 history.pushState(null, null, link.hash); 66 } 67 68 self.setTimer(); 69 70 // After scrolling ends 71 if (typeof self.options.onComplete === "function") { 72 self.options.onComplete(); 73 } 74 }); 75 } 76 }, 77 78 scrollTo: function ($elem, callback) { 79 var self = this; 80 var target = self.getCoords($elem).top; 81 var called = false; 82 83 self.$htmlbody.stop().animate( 84 { scrollTop: target }, 85 { 86 duration: self.options.speed, 87 easing: self.options.easing, 88 complete: function () { 89 if (typeof callback === "function" && !called) { 90 callback(); 91 } 92 called = true; 93 }, 94 } 95 ); 96 }, 97 98 setTimer: function () { 99 var self = this; 100 101 self.$window.on("scroll.singlePageNav", function () { 102 self.didScroll = true; 103 }); 104 105 self.timer = setInterval(function () { 106 if (self.didScroll) { 107 self.didScroll = false; 108 self.checkPosition(); 109 } 110 }, 250); 111 }, 112 113 clearTimer: function () { 114 clearInterval(this.timer); 115 this.$window.off("scroll.singlePageNav"); 116 this.didScroll = false; 117 }, 118 119 // Check the scroll position and set the active section 120 checkPosition: function () { 121 var scrollPos = this.$window.scrollTop(); 122 var currentSection = this.getCurrentSection(scrollPos); 123 if (currentSection !== null) { 124 this.setActiveLink(currentSection); 125 } 126 }, 127 128 getCoords: function ($elem) { 129 return { 130 top: Math.round($elem.offset().top) - this.options.offset, 131 }; 132 }, 133 134 setActiveLink: function (href) { 135 var $activeLink = this.$container.find("a[href$='" + href + "']"); 136 137 if (!$activeLink.hasClass(this.options.currentClass)) { 138 this.$links.removeClass(this.options.currentClass); 139 $activeLink.addClass(this.options.currentClass); 140 } 141 }, 142 143 getCurrentSection: function (scrollPos) { 144 var i, hash, coords, section; 145 146 for (i = 0; i < this.$links.length; i++) { 147 hash = this.$links[i].hash; 148 149 if ($(hash).length) { 150 coords = this.getCoords($(hash)); 151 152 if (scrollPos >= coords.top - this.options.threshold) { 153 section = hash; 154 } 155 } 156 } 157 158 // The current section or the first link if it is found 159 return section || (this.$links.length === 0 ? null : this.$links[0].hash); 160 }, 161 }; 162 163 $.fn.singlePageNav = function (options) { 164 return this.each(function () { 165 var singlePageNav = Object.create(SinglePageNav); 166 singlePageNav.init(options, this); 167 });
168 }; 169 170 $.fn.singlePageNav.defaults = { 171 offset: 0, 172 threshold: 120, 173 speed: 400, 174 currentClass: "current", 175 easing: "swing", 176 updateHash: false, 177 filter: "", 178 onComplete: false, 179 beforeStart: false, 180 }; 181})(jQuery, window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.