1/* 2 * jQuery One Page Nav Plugin 3 * http://github.com/davist11/jQuery-One-Page-Nav 4 * 5 * Copyright (c) 2010 Trevor Davis (http://trevordavis.net) 6 * Dual licensed under the MIT and GPL licenses. 7 * Uses the same license as jQuery, see: 8 * http://jquery.org/license 9 * 10 * @version 3.0.0 11 * 12 * Example usage: 13 * $('#nav').onePageNav({ 14 * currentClass: 'current', 15 * changeHash: false, 16 * scrollSpeed: 750 17 * }); 18 */ 19 20; 21(function ($, window, document, undefined) { 22 23 // our plugin constructor 24 var OnePageNav = function (elem, options) { 25 this.elem = elem; 26 this.$elem = $(elem); 27 this.options = options; 28 this.metadata = this.$elem.data('plugin-options'); 29 this.$win = $(window); 30 this.sections = {}; 31 this.didScroll = false; 32 this.$doc = $(document); 33 this.docHeight = this.$doc.height(); 34 }; 35 36 // the plugin prototype 37 OnePageNav.prototype = { 38 defaults: { 39 navItems: 'a[href*="#"]', 40 currentClass: 'current', 41 changeHash: false, 42 easing: 'swing', 43 filter: '', 44 scrollSpeed: 750, 45 scrollOffset: 0, 46 scrollThreshold: 0.5, 47 begin: false, 48 end: false, 49 scrollChange: false 50 }, 51 52 init: function () { 53 // Introduce defaults that can be extended either 54 // globally or using an object literal. 55 this.config = $.extend({}, this.defaults, this.options, this.metadata); 56 57 this.$nav = this.$elem.find(this.config.navItems); 58 59 //Filter any links out of the nav 60 if (this.config.filter !== '') { 61 this.$nav = this.$nav.filter(this.config.filter); 62 } 63 64 //Handle clicks on the nav 65 this.$nav.on('click.onePageNav', $.proxy(this.handleClick, this)); 66 67 //Get the section positions 68 this.getPositions(); 69 70 //Handle scroll changes 71 this.bindInterval(); 72 73 //Update the positions on resize too 74 this.$win.on('resize.onePageNav', $.proxy(this.getPositions, this)); 75 76 return this; 77 }, 78 79 adjustNav: function (self, $parent) { 80 self.$elem.find('.' + self.config.currentClass).removeClass(self.config.currentClass); 81 $parent.addClass(self.config.currentClass); 82 }, 83 84 bindInterval: function () { 85 var self = this; 86 var docHeight; 87 88 self.$win.on('scroll.onePageNav', function () { 89 self.didScroll = true; 90 }); 91 92 self.t = setInterval(function () { 93 docHeight = self.$doc.height(); 94 95 //If it was scrolled 96 if (self.didScroll) { 97 self.didScroll = false; 98 self.scrollChange(); 99 } 100 101 //If the document height changes 102 if (docHeight !== self.docHeight) { 103 self.docHeight = docHeight; 104 self.getPositions(); 105 } 106 }, 250); 107 }, 108 109 getHash: function ($link) { 110 return $link.attr('href').split('#')[1]; 111 }, 112 113 getPositions: function () { 114 var self = this; 115 var linkHref; 116 var topPos; 117 var $target; 118 119 self.$nav.each(function () { 120 linkHref = self.getHash($(this)); 121 $target = $('#' + linkHref); 122 123 if ($target.length) { 124 topPos = $target.offset().top; 125 self.sections[linkHref] = Math.round(topPos) - self.config.scrollOffset; 126 } 127 }); 128 }, 129 130 getSection: function (windowPos) { 131 var returnValue = null; 132 var windowHeight = Math.round(this.$win.height() * this.config.scrollThreshold); 133 134 for (var section in this.sections) { 135 if ((this.sections[section] - windowHeight) < windowPos) { 136 returnValue = section; 137 } 138 } 139 140 return returnValue; 141 }, 142 143 handleClick: function (e) { 144 var self = this; 145 var $link = $(e.currentTarget); 146 var $parent = $link.parent(); 147 var newLoc = '#' + self.getHash($link); 148 149 //if(!$parent.hasClass(self.config.currentClass)) { 150 if ($(newLoc).length > 0) { 151 //Start callback 152 if (self.config.begin) { 153 self.config.begin(); 154 } 155 156 //Change the highlighted nav item 157 self.adjustNav(self, $parent); 158 159 //Removing the auto-adjust on scroll 160 self.unbindInterval(); 161 162 //Scroll to the correct position 163 self.scrollTo(newLoc, function () { 164 //Do we need to change the hash? 165 if (self.config.changeHash) { 166 window.location.hash = newLoc; 167 } 168 169 //Add the auto-adjust on scroll back in 170 self.bindInterval(); 171 172 //End callback 173 if (self.config.end) { 174 self.config.end(); 175 } 176 }); 177 e.preventDefault(); 178 } 179 //} 180 181 182 }, 183 184 scrollChange: function () { 185 var windowTop = this.$win.scrollTop();
186 var position = this.getSection(windowTop); 187 var $parent; 188 189 //If the position is set 190 if (position !== null) { 191 $parent = this.$elem.find('a[href$="#' + position + '"]').parent(); 192 193 //If it's not already the current section 194 if (!$parent.hasClass(this.config.currentClass)) { 195 //Change the highlighted nav item 196 this.adjustNav(this, $parent); 197 198 //If there is a scrollChange callback 199 if (this.config.scrollChange) { 200 this.config.scrollChange($parent); 201 } 202 } 203 } 204 }, 205 206 scrollTo: function (target, callback) { 207 if ($(target).length > 0) { 208 var offset = $(target).offset().top; 209 210 $('html, body').animate({ 211 scrollTop: offset - this.config.scrollOffset 212 }, this.config.scrollSpeed, this.config.easing, callback); 213 } 214 }, 215 216 unbindInterval: function () { 217 clearInterval(this.t); 218 this.$win.unbind('scroll.onePageNav'); 219 } 220 }; 221 222 OnePageNav.defaults = OnePageNav.prototype.defaults; 223 224 $.fn.onePageNav = function (options) { 225 return this.each(function () { 226 new OnePageNav(this, options).init(); 227 }); 228 }; 229 230})(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.