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