-
Notifications
You must be signed in to change notification settings - Fork 6
/
jquery.stickyNav.js
126 lines (100 loc) · 3.69 KB
/
jquery.stickyNav.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
;
(function ($, window) {
'use strict';
$.fn.stickyNavbar = function (prop) {
var options = $.extend({
header: '.header',
activeClass: 'active',
attachActiveClassTo: 'li',
animationDuration: 500,
easing: 'swing',
disableOnMobile: true,
mobileWidth: 640
}, prop);
var header = options.header ? $(options.header) : undefined
, navBar = $(this);
if (navBar.length == 0) {
return;
}
if (options.disableOnMobile && $(window).width() <= options.mobileWidth) {
return;
}
var stickyPosition = header ? header.outerHeight(true) : 0
, heroHeight = navBar.offset().top - stickyPosition,
navBarHeight = navBar.outerHeight(true);
// collect all the sections for jumping
var sections = new jQuery();
navBar.find('li a').map(function () {
var id = $(this).attr('href');
sections = sections.add($(id));
});
// because we have header/banner so there is offset for sections
var sectionsOffset = stickyPosition + navBarHeight + 2;
// the active menu in navigator
var activeOne;
function initSecondaryNav() {
navBar.before('<div class="nav-placeholder"></div>');
$('.nav-placeholder').css('padding-bottom', navBarHeight + 'px');
$('.nav-placeholder').css('padding-bottom', navBarHeight + 'px');
$('.nav-placeholder').css('height', '0px');
$('.nav-placeholder').css('z-index', '-9999');
navBar.css('position', 'fixed').css('margin-top', -navBarHeight + 'px');
scrollCallback();
}
function addActiveState(sections) {
var windowScrollHeight = $(window).scrollTop();
sections.each(function (index) {
var top = $(this).offset().top
, bottom = $(this).outerHeight(true) + top;
windowScrollHeight = $(window).scrollTop();
if (
(windowScrollHeight > top - sectionsOffset && windowScrollHeight < bottom - sectionsOffset)
|| (index == 0 && windowScrollHeight < top - sectionsOffset)
|| (index == sections.length - 1 && windowScrollHeight > bottom - sectionsOffset)
) {
if (activeOne) {
activeOne.removeClass(options.activeClass);
}
activeOne = options.attachActiveClassTo === 'a' ?
navBar.find('li a[href~="#' + this.id + '"]')
: navBar.find('li a[href~="#' + this.id + '"]').parents('li');
activeOne.addClass(options.activeClass);
}
}
);
}
function positionNavBar() {
if ($(window).scrollTop() >= 0) {
$(window).scrollTop() < heroHeight
? navBar.css('margin-top', -navBarHeight - $(window).scrollTop() + 'px')
: navBar.css('margin-top', -navBarHeight - heroHeight + 'px');
}
}
function scrollCallback() {
positionNavBar();
// put this into next tick
setTimeout(function () {
addActiveState(sections);
}, 1);
}
function smoothScroll(e) {
e.preventDefault();
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html, body').stop().animate({
scrollTop: target.offset().top - stickyPosition - navBarHeight
}, {
duration: options.animationDuration,
easing: options.easing
});
}
}
}
initSecondaryNav();
$(window).on('scroll', scrollCallback);
$(this).find(' a[href*=#]:not([href=#])').on('click', smoothScroll);
}
})
(jQuery, window, document);