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 23 init: function(options, container) { 24 25 this.options = $.extend({}, $.fn.singlePageNav.defaults, options); 26 27 this.container = container; 28 this.$container = $(container); 29 this.$links = this.$container.find('a'); 30 31 if (this.options.filter !== '') { 32 this.$links = this.$links.filter(this.options.filter); 33 } 34 35 this.$window = $(window); 36 this.$htmlbody = $('html, body'); 37 38 this.$links.on('click.singlePageNav', $.proxy(this.handleClick, this)); 39 40 this.didScroll = false; 41 this.checkPosition(); 42 this.setTimer(); 43 }, 44 45 handleClick: function(e) { 46 var self = this, 47 link = e.currentTarget, 48 $elem = $(link.hash); 49 50 e.preventDefault(); 51 52 if ($elem.length) { // Make sure the target elem exists 53 54 // Prevent active link from cycling during the scroll 55 self.clearTimer(); 56 57 // Before scrolling starts 58 if (typeof self.options.beforeStart === 'function') { 59 self.options.beforeStart(); 60 } 61 62 self.setActiveLink(link.hash); 63 64 self.scrollTo($elem, function() { 65 66 if (self.options.updateHash && history.pushState) { 67 history.pushState(null,null, link.hash); 68 } 69 70 self.setTimer(); 71 72 // After scrolling ends 73 if (typeof self.options.onComplete === 'function') { 74 self.options.onComplete(); 75 } 76 }); 77 } 78 }, 79 80 scrollTo: function($elem, callback) { 81 var self = this; 82 var target = self.getCoords($elem).top; 83 var called = false; 84 85 self.$htmlbody.stop().animate( 86 {scrollTop: target}, 87 { 88 duration: self.options.speed, 89 easing: self.options.easing, 90 complete: function() { 91 if (typeof callback === 'function' && !called) { 92 callback(); 93 } 94 called = true; 95 } 96 } 97 ); 98 }, 99 100 setTimer: function() { 101 var self = this; 102 103 self.$window.on('scroll.singlePageNav', function() { 104 self.didScroll = true; 105 }); 106 107 self.timer = setInterval(function() { 108 if (self.didScroll) { 109 self.didScroll = false; 110 self.checkPosition(); 111 } 112 }, 250); 113 }, 114 115 clearTimer: function() { 116 clearInterval(this.timer); 117 this.$window.off('scroll.singlePageNav'); 118 this.didScroll = false; 119 }, 120 121 // Check the scroll position and set the active section 122 checkPosition: function() { 123 var scrollPos = this.$window.scrollTop(); 124 var currentSection = this.getCurrentSection(scrollPos); 125 if(currentSection!==null) { 126 this.setActiveLink(currentSection); 127 } 128 }, 129 130 getCoords: function($elem) { 131 var row_offset = $elem.attr('data-offset'); 132 133 row_offset = (row_offset != undefined && row_offset != '') ? row_offset : 0 ; 134 135 return { 136 top: Math.round($elem.offset().top) - this.options.offset - row_offset 137 }; 138 }, 139
140 setActiveLink: function(href) { 141 var $activeLink = this.$container.find("a[href$='" + href + "']"); 142 143 if (!$activeLink.hasClass(this.options.currentClass)) { 144 this.$links.removeClass(this.options.currentClass); 145 $activeLink.addClass(this.options.currentClass); 146 } 147 }, 148 149 getCurrentSection: function(scrollPos) { 150 var i, hash, coords, section; 151 152 for (i = 0; i < this.$links.length; i++) { 153 hash = this.$links[i].hash; 154 155 if ($(hash).length) { 156 coords = this.getCoords($(hash)); 157 158 if (scrollPos >= coords.top - this.options.threshold) { 159 section = hash; 160 } 161 } 162 } 163 164 // The current section or the first link if it is found 165 return section || ((this.$links.length===0) ? (null) : (this.$links[0].hash)); 166 } 167 }; 168 169 $.fn.singlePageNav = function(options) { 170 return this.each(function() { 171 var singlePageNav = Object.create(SinglePageNav); 172 singlePageNav.init(options, this); 173 }); 174 }; 175 176 $.fn.singlePageNav.defaults = { 177 offset: 0, 178 threshold: 120, 179 speed: 400, 180 currentClass: 'current', 181 easing: 'swing', 182 updateHash: false, 183 filter: '', 184 onComplete: false, 185 beforeStart: false 186 }; 187 188})(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.