ratchet_design 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/app/assets/images/ratchet/favicon.ico +0 -0
- data/app/assets/javascripts/ratchet/_svg.js +55 -0
- data/app/assets/javascripts/ratchet/base/form.js +220 -0
- data/app/assets/javascripts/ratchet/base/mobilemenu.js +62 -0
- data/app/assets/javascripts/ratchet/base/validation.js +230 -0
- data/app/assets/javascripts/ratchet/core.js +92 -0
- data/app/assets/javascripts/ratchet/enhancement/_collapse.js +96 -0
- data/app/assets/javascripts/ratchet/enhancement/_lightbox.js +93 -0
- data/app/assets/javascripts/ratchet/enhancement/_swap.js +120 -0
- data/app/assets/javascripts/ratchet/enhancement/_switcheroo.js +28 -0
- data/app/assets/javascripts/ratchet/enhancement/_textcounter.js +92 -0
- data/app/assets/javascripts/ratchet/enhancement/loader.js +77 -0
- data/app/assets/javascripts/ratchet/enhancement/notice.js +70 -0
- data/app/assets/javascripts/ratchet/enhancement/sticky.js +128 -0
- data/app/assets/javascripts/ratchet/enhancement/waypoints.js +328 -0
- data/app/assets/javascripts/ratchet/shim/classlist.js +234 -0
- data/app/assets/javascripts/ratchet/shim/object.assign.js +30 -0
- data/app/assets/javascripts/ratchet/utility/compile_data.js +32 -0
- data/app/assets/javascripts/ratchet/utility/from_top.js +14 -0
- data/app/assets/javascripts/ratchet/utility/full_stop.js +55 -0
- data/app/assets/javascripts/ratchet/utility/get_closest.js +20 -0
- data/app/assets/javascripts/ratchet/utility/get_next.js +17 -0
- data/app/assets/javascripts/ratchet/utility/load_font.js +72 -0
- data/app/assets/javascripts/ratchet/utility/load_script.js +34 -0
- data/app/assets/javascripts/ratchet/utility/matches.js +15 -0
- data/app/assets/javascripts/ratchet/utility/scroll_to.js +74 -0
- data/app/assets/javascripts/ratchet/utility/throttle.js +25 -0
- data/app/assets/javascripts/ratchet/utility/timeout.js +45 -0
- data/app/assets/javascripts/ratchet/utility/unhover.js +56 -0
- data/app/assets/javascripts/ratchet/utility/word_count.js +15 -0
- data/app/assets/stylesheets/ratchet/_core.scss +20 -0
- data/app/assets/stylesheets/ratchet/base/_button.scss +101 -0
- data/app/assets/stylesheets/ratchet/base/_document.scss +306 -0
- data/app/assets/stylesheets/ratchet/base/_form.scss +614 -0
- data/app/assets/stylesheets/ratchet/base/_list.scss +114 -0
- data/app/assets/stylesheets/ratchet/base/_media.scss +41 -0
- data/app/assets/stylesheets/ratchet/base/_table.scss +81 -0
- data/app/assets/stylesheets/ratchet/base/_text.scss +411 -0
- data/app/assets/stylesheets/ratchet/enhancement/_contrast-section.scss +22 -0
- data/app/assets/stylesheets/ratchet/enhancement/_feature.scss +49 -0
- data/app/assets/stylesheets/ratchet/enhancement/_hero.scss +44 -0
- data/app/assets/stylesheets/ratchet/enhancement/_loader.scss +109 -0
- data/app/assets/stylesheets/ratchet/enhancement/_notice.scss +74 -0
- data/app/assets/stylesheets/ratchet/enhancement/_signup.scss +206 -0
- data/app/assets/stylesheets/ratchet/enhancement/_sticky-sidebar.scss +36 -0
- data/app/assets/stylesheets/ratchet/fonts-woff.css +55 -0
- data/app/assets/stylesheets/ratchet/fonts-woff2.css +55 -0
- data/app/assets/stylesheets/ratchet/utility/_global.scss +255 -0
- data/app/assets/stylesheets/ratchet/utility/_grid.scss +102 -0
- data/app/assets/svgs/ratchet/facebook.svg +1 -0
- data/app/assets/svgs/ratchet/github.svg +1 -0
- data/app/assets/svgs/ratchet/google-plus.svg +1 -0
- data/app/assets/svgs/ratchet/ibm.svg +1 -0
- data/app/assets/svgs/ratchet/inbox.svg +1 -0
- data/app/assets/svgs/ratchet/linkedin.svg +1 -0
- data/app/assets/svgs/ratchet/ratchet.svg +1 -0
- data/app/assets/svgs/ratchet/search.svg +1 -0
- data/app/assets/svgs/ratchet/subscribe.svg +1 -0
- data/app/assets/svgs/ratchet/twitter.svg +1 -0
- data/app/assets/svgs/ratchet/y-combinator.svg +1 -0
- data/app/helpers/ratchet/application_helper.rb +51 -0
- data/app/views/layouts/ratchet/default.html.slim +61 -0
- data/app/views/shared/ratchet/_footer.html.slim +2 -0
- data/app/views/shared/ratchet/_header.html.slim +17 -0
- data/app/views/shared/ratchet/_icons.html.slim +89 -0
- data/lib/ratchet_design.rb +12 -0
- data/lib/ratchet_design/version.rb +3 -0
- data/public/assets/ratchet/core-0.1.0.js +103 -0
- data/public/assets/ratchet/core-0.1.0.js.gz +0 -0
- data/public/assets/ratchet/core-0.1.0.map.json +1 -0
- data/public/assets/ratchet/fonts-woff-0.1.0.css +55 -0
- data/public/assets/ratchet/fonts-woff-0.1.0.css.gz +0 -0
- data/public/assets/ratchet/fonts-woff2-0.1.0.css +55 -0
- data/public/assets/ratchet/fonts-woff2-0.1.0.css.gz +0 -0
- metadata +177 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
/**
|
2
|
+
* Loader 0.0.1
|
3
|
+
* Compose loader module
|
4
|
+
* @author Kyle Foster (@hkfoster)
|
5
|
+
* @license MIT
|
6
|
+
**/
|
7
|
+
|
8
|
+
// Public API function
|
9
|
+
var loader = function( settings ) {
|
10
|
+
|
11
|
+
// Overridable defaults
|
12
|
+
var defaults = {
|
13
|
+
selector : document.body,
|
14
|
+
loaderClass : 'loader',
|
15
|
+
loadingMessage : 'Hang tight…',
|
16
|
+
loadingClass : 'loading',
|
17
|
+
successMessage : 'Got it!',
|
18
|
+
successClass : 'success',
|
19
|
+
failureMessage : 'Hold up!',
|
20
|
+
failureClass : 'failure'
|
21
|
+
};
|
22
|
+
|
23
|
+
// Extend defaults
|
24
|
+
var options = Object.assign( {}, defaults, settings );
|
25
|
+
|
26
|
+
// Create and prepend loader element
|
27
|
+
options.selector.insertAdjacentHTML( 'afterbegin', '<div class="' + options.loaderClass + '"></div>' );
|
28
|
+
|
29
|
+
// Cache loader element
|
30
|
+
var element = document.querySelector( 'div.' + options.loaderClass );
|
31
|
+
|
32
|
+
// Show loader icon function
|
33
|
+
var show = function( state ) {
|
34
|
+
|
35
|
+
// Loader pending state
|
36
|
+
if ( state === 'pending' ) {
|
37
|
+
|
38
|
+
element.textContent = options.loadingMessage;
|
39
|
+
element.classList.remove( options.successClass, options.failureClass );
|
40
|
+
element.classList.add( options.loadingClass );
|
41
|
+
|
42
|
+
// Loader failure state
|
43
|
+
} else if ( state === 'failure' ) {
|
44
|
+
|
45
|
+
element.textContent = options.failureMessage;
|
46
|
+
element.classList.remove( options.loadingClass );
|
47
|
+
element.classList.add( options.failureClass );
|
48
|
+
|
49
|
+
// Loader success state
|
50
|
+
} else if ( state === 'success' ) {
|
51
|
+
|
52
|
+
element.textContent = options.successMessage;
|
53
|
+
element.classList.remove( options.loadingClass );
|
54
|
+
element.classList.add( options.successClass );
|
55
|
+
|
56
|
+
}
|
57
|
+
|
58
|
+
};
|
59
|
+
|
60
|
+
// Hide loader icon function
|
61
|
+
var hide = function() {
|
62
|
+
|
63
|
+
// Remove state classes altogether
|
64
|
+
element.classList.remove( options.loadingClass, options.successClass, options.failureClass );
|
65
|
+
|
66
|
+
};
|
67
|
+
|
68
|
+
// Public functions
|
69
|
+
return {
|
70
|
+
show : show,
|
71
|
+
hide : hide
|
72
|
+
};
|
73
|
+
|
74
|
+
};
|
75
|
+
|
76
|
+
// Public API
|
77
|
+
module.exports = loader;
|
@@ -0,0 +1,70 @@
|
|
1
|
+
/**
|
2
|
+
* Notice 0.0.1
|
3
|
+
* Compose notice module
|
4
|
+
* @author Kyle Foster (@hkfoster)
|
5
|
+
* @license MIT
|
6
|
+
**/
|
7
|
+
|
8
|
+
// Public API function
|
9
|
+
var notice = function( element, settings ) {
|
10
|
+
|
11
|
+
// Overridable defaults
|
12
|
+
var defaults = {
|
13
|
+
noticeName : 'notice',
|
14
|
+
noticeClass : 'notice',
|
15
|
+
noticeMessage : '[your notice message here]'
|
16
|
+
};
|
17
|
+
|
18
|
+
// Scoped variables
|
19
|
+
var options = Object.assign( {}, defaults, settings ),
|
20
|
+
selector = document.querySelector( element ),
|
21
|
+
cookieName = 'dismiss-' + options.noticeName;
|
22
|
+
|
23
|
+
// Only run if selector exists & no dismiss cookie is found
|
24
|
+
if ( !selector || getCookie( cookieName ) ) return false;
|
25
|
+
|
26
|
+
// Uncomment for development
|
27
|
+
// deleteCookie( cookieName );
|
28
|
+
|
29
|
+
// Create and append notice
|
30
|
+
var html = '<aside class="' + options.noticeClass + '">' + options.noticeMessage + '<a href="#?" class="close-btn"></a></aside>'
|
31
|
+
document.querySelector( 'main' ).insertAdjacentHTML( 'afterbegin', html );
|
32
|
+
|
33
|
+
// Listen for close button click
|
34
|
+
selector.querySelector( '.' + options.noticeClass + ' > .close-btn' ).addEventListener( 'click', dismissNotice, false );
|
35
|
+
|
36
|
+
// Dismiss notice on close
|
37
|
+
function dismissNotice( event ) {
|
38
|
+
|
39
|
+
// Prevent default behavior
|
40
|
+
event.preventDefault();
|
41
|
+
|
42
|
+
// Cache notice element
|
43
|
+
var noticeElem = selector.querySelector( '.' + options.noticeClass );
|
44
|
+
|
45
|
+
// Remove notice from page
|
46
|
+
selector.removeChild( noticeElem );
|
47
|
+
|
48
|
+
// Set cookie to prevent it from returning
|
49
|
+
document.cookie = cookieName + '=true; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/';
|
50
|
+
|
51
|
+
}
|
52
|
+
|
53
|
+
// Check for cookie by name
|
54
|
+
function getCookie( name ) {
|
55
|
+
var value = '; ' + document.cookie;
|
56
|
+
var parts = value.split( '; ' + name + '=' );
|
57
|
+
if ( parts.length == 2 ) return parts.pop().split( ';' ).shift();
|
58
|
+
}
|
59
|
+
|
60
|
+
// Delete a cookie by setting the date of expiry to yesterday
|
61
|
+
function deleteCookie( name ) {
|
62
|
+
var date = new Date();
|
63
|
+
date.setDate( date.getDate() -1 );
|
64
|
+
document.cookie = escape( name ) + '=;expires=' + date;
|
65
|
+
}
|
66
|
+
|
67
|
+
};
|
68
|
+
|
69
|
+
// Public API
|
70
|
+
module.exports = notice;
|
@@ -0,0 +1,128 @@
|
|
1
|
+
/**
|
2
|
+
* Sticky 0.0.3
|
3
|
+
* Compose sticky elements module
|
4
|
+
* @author Kyle Foster (@hkfoster)
|
5
|
+
* @license MIT
|
6
|
+
**/
|
7
|
+
|
8
|
+
// Dependencies
|
9
|
+
var throttle = require( '../utility/throttle' ),
|
10
|
+
fromTop = require( '../utility/from_top' );
|
11
|
+
|
12
|
+
// Public API function
|
13
|
+
var sticky = function( element, settings ) {
|
14
|
+
|
15
|
+
// Overridable defaults
|
16
|
+
var defaults = {
|
17
|
+
topPadding : false,
|
18
|
+
initWidth : '700px',
|
19
|
+
stickyClass : 'sticky',
|
20
|
+
anchorPoint : null
|
21
|
+
};
|
22
|
+
|
23
|
+
// Scoped variables
|
24
|
+
var options = Object.assign( {}, defaults, settings ),
|
25
|
+
selector = document.querySelector( element );
|
26
|
+
|
27
|
+
// If selector is not present
|
28
|
+
if ( !selector ) {
|
29
|
+
|
30
|
+
// Abort
|
31
|
+
return false;
|
32
|
+
|
33
|
+
// Otherwise attach listeners
|
34
|
+
} else {
|
35
|
+
|
36
|
+
// Scoped variables
|
37
|
+
var topPadding = ( options.topPadding === true ) ? parseInt( window.getComputedStyle( selector, null ).getPropertyValue( 'padding-top' ) ) : 0,
|
38
|
+
widthQuery = window.matchMedia( '(min-width: ' + options.initWidth + ')' ),
|
39
|
+
topOffset = fromTop( selector ) + topPadding,
|
40
|
+
elemHeight = selector.offsetHeight,
|
41
|
+
anchorInit = options.anchorPoint,
|
42
|
+
docBody = document.body,
|
43
|
+
docHeight,
|
44
|
+
winHeight;
|
45
|
+
|
46
|
+
// Resize throttle function init
|
47
|
+
throttle( 'resize', 'optimizedResize' );
|
48
|
+
|
49
|
+
// Scroll throttle function init
|
50
|
+
throttle( 'scroll', 'optimizedScroll' );
|
51
|
+
|
52
|
+
// Call listener function explicitly at run time
|
53
|
+
queryHandler( widthQuery );
|
54
|
+
|
55
|
+
// Attach listener function to listen in on state changes
|
56
|
+
widthQuery.addListener( queryHandler );
|
57
|
+
|
58
|
+
}
|
59
|
+
|
60
|
+
// Media query handler function
|
61
|
+
function queryHandler( condition ) {
|
62
|
+
|
63
|
+
// If media query matches
|
64
|
+
if ( condition.matches ) {
|
65
|
+
|
66
|
+
// Call resize listener function explicitly at run time
|
67
|
+
resizeHandler();
|
68
|
+
|
69
|
+
// Resize function listener
|
70
|
+
window.addEventListener( 'optimizedResize', resizeHandler, false );
|
71
|
+
|
72
|
+
// Call scroll listener function explicitly at run time
|
73
|
+
scrollHandler();
|
74
|
+
|
75
|
+
// Scroll function listener
|
76
|
+
window.addEventListener( 'optimizedScroll', scrollHandler, false );
|
77
|
+
|
78
|
+
} else {
|
79
|
+
|
80
|
+
// Reset styles
|
81
|
+
docBody.classList.remove( 'sticky' );
|
82
|
+
|
83
|
+
// Remove resize listener
|
84
|
+
window.removeEventListener( 'optimizedResize', resizeHandler, false );
|
85
|
+
|
86
|
+
// Remove scroll listener
|
87
|
+
window.removeEventListener( 'optimizedScroll', scrollHandler, false );
|
88
|
+
|
89
|
+
}
|
90
|
+
|
91
|
+
}
|
92
|
+
|
93
|
+
// Resize handler function
|
94
|
+
function resizeHandler() {
|
95
|
+
|
96
|
+
// Update document height variable
|
97
|
+
docHeight = document.body.scrollHeight;
|
98
|
+
|
99
|
+
// Update window height variable
|
100
|
+
winHeight = window.innerHeight;
|
101
|
+
|
102
|
+
}
|
103
|
+
|
104
|
+
// Scroll handler function
|
105
|
+
function scrollHandler() {
|
106
|
+
|
107
|
+
// Scoped variables
|
108
|
+
var newScrollY = window.pageYOffset,
|
109
|
+
pastOffset = newScrollY > topOffset,
|
110
|
+
anchored = ( anchorInit ) ? newScrollY >= docHeight - elemHeight - anchorInit + topPadding : null;
|
111
|
+
|
112
|
+
// Where the magic happens
|
113
|
+
if ( pastOffset && !anchored ) {
|
114
|
+
docBody.classList.remove( 'anchored' );
|
115
|
+
docBody.classList.add( 'sticky' );
|
116
|
+
} else if ( pastOffset && anchored ) {
|
117
|
+
docBody.classList.remove( 'sticky' );
|
118
|
+
docBody.classList.add( 'anchored' );
|
119
|
+
} else {
|
120
|
+
docBody.classList.remove( 'sticky' );
|
121
|
+
}
|
122
|
+
|
123
|
+
}
|
124
|
+
|
125
|
+
};
|
126
|
+
|
127
|
+
// Public API
|
128
|
+
module.exports = sticky;
|
@@ -0,0 +1,328 @@
|
|
1
|
+
/**
|
2
|
+
* Waypoints 0.0.4
|
3
|
+
* Compose waypoint navigation module
|
4
|
+
* @author Kyle Foster (@hkfoster)
|
5
|
+
* @license MIT
|
6
|
+
**/
|
7
|
+
|
8
|
+
// Dependencies
|
9
|
+
var matches = require( '../utility/matches' ),
|
10
|
+
fromTop = require( '../utility/from_top' ),
|
11
|
+
scrollTo = require( '../utility/scroll_to' ),
|
12
|
+
getClosest = require( '../utility/get_closest' ),
|
13
|
+
throttle = require( '../utility/throttle' );
|
14
|
+
|
15
|
+
// Public API function
|
16
|
+
var waypoints = function( elements, settings ) {
|
17
|
+
|
18
|
+
// Overridable defaults
|
19
|
+
var defaults = {
|
20
|
+
initWidth : '700px',
|
21
|
+
navigation : '.secondary',
|
22
|
+
activeAnchor : 'active',
|
23
|
+
elemOffset : 0,
|
24
|
+
showLandmarks : false,
|
25
|
+
landmarkSelector : '.landmark',
|
26
|
+
activeLandmark : 'pinned',
|
27
|
+
};
|
28
|
+
|
29
|
+
// Scoped variables
|
30
|
+
var options = Object.assign( {}, defaults, settings ),
|
31
|
+
selectors = document.querySelectorAll( elements );
|
32
|
+
|
33
|
+
// If selectors are not present
|
34
|
+
if ( !selectors.length ) {
|
35
|
+
|
36
|
+
// Abort
|
37
|
+
return false;
|
38
|
+
|
39
|
+
// Otherwise attach listeners
|
40
|
+
} else {
|
41
|
+
|
42
|
+
// Scoped variables
|
43
|
+
var navigation = document.querySelector( options.navigation ),
|
44
|
+
widthQuery = window.matchMedia( '(min-width: ' + options.initWidth + ')' ),
|
45
|
+
coordinates = [],
|
46
|
+
oldActiveItem,
|
47
|
+
windowHash,
|
48
|
+
docHeight,
|
49
|
+
winHeight;
|
50
|
+
|
51
|
+
// If hash is present
|
52
|
+
if ( window.location.hash ) {
|
53
|
+
|
54
|
+
// Cache it
|
55
|
+
windowHash = window.location.hash.replace( '#', '' );
|
56
|
+
|
57
|
+
// Then delete it to prevent default page scroll
|
58
|
+
window.location.hash = '';
|
59
|
+
|
60
|
+
// And replace it
|
61
|
+
history.replaceState( null, '', '#' + windowHash );
|
62
|
+
|
63
|
+
}
|
64
|
+
|
65
|
+
// Resize throttle function init
|
66
|
+
throttle( 'resize', 'optimizedResize' );
|
67
|
+
|
68
|
+
// Scroll throttle function init
|
69
|
+
throttle( 'scroll', 'optimizedScroll' );
|
70
|
+
|
71
|
+
// Only run once the window is loaded
|
72
|
+
window.addEventListener( 'load', function() {
|
73
|
+
|
74
|
+
// Call listener function explicitly at run time
|
75
|
+
queryHandler( widthQuery );
|
76
|
+
|
77
|
+
// Attach listener function to listen in on state changes
|
78
|
+
widthQuery.addListener( queryHandler );
|
79
|
+
|
80
|
+
}, false );
|
81
|
+
|
82
|
+
}
|
83
|
+
|
84
|
+
// Media query handler function
|
85
|
+
function queryHandler( condition ) {
|
86
|
+
|
87
|
+
// If media query matches
|
88
|
+
if ( condition.matches ) {
|
89
|
+
|
90
|
+
// Call resize listener function explicitly at run time
|
91
|
+
resizeHandler();
|
92
|
+
|
93
|
+
// Resize throttle function init
|
94
|
+
window.addEventListener( 'optimizedResize', resizeHandler, false );
|
95
|
+
|
96
|
+
// Call scroll listener function explicitly at run time
|
97
|
+
scrollHandler();
|
98
|
+
|
99
|
+
// Scroll function listener
|
100
|
+
window.addEventListener( 'optimizedScroll', scrollHandler, false );
|
101
|
+
|
102
|
+
// Click function listener
|
103
|
+
navigation.addEventListener( 'click', clickHandler, false );
|
104
|
+
|
105
|
+
// Call hash change listener function explicitly at run time
|
106
|
+
hashHandler();
|
107
|
+
|
108
|
+
// Hash change function listener
|
109
|
+
window.addEventListener( 'hashchange', hashHandler, false );
|
110
|
+
|
111
|
+
// Otherwise…
|
112
|
+
} else {
|
113
|
+
|
114
|
+
// Remove resize listener
|
115
|
+
window.removeEventListener( 'optimizedResize', resizeHandler, false );
|
116
|
+
|
117
|
+
// Remove scroll listener
|
118
|
+
window.removeEventListener( 'optimizedScroll', scrollHandler, false );
|
119
|
+
|
120
|
+
// Remove click listener
|
121
|
+
navigation.removeEventListener( 'click', clickHandler, false );
|
122
|
+
|
123
|
+
// Remove hash change listener
|
124
|
+
window.removeEventListener( 'hashchange', hashHandler, false );
|
125
|
+
|
126
|
+
}
|
127
|
+
|
128
|
+
}
|
129
|
+
|
130
|
+
// Resize handler function
|
131
|
+
function resizeHandler() {
|
132
|
+
|
133
|
+
// Update document height variable
|
134
|
+
docHeight = document.body.scrollHeight;
|
135
|
+
|
136
|
+
// Update window height variable
|
137
|
+
winHeight = window.innerHeight;
|
138
|
+
|
139
|
+
// Loop through waypoints
|
140
|
+
for ( var i = 0; i < selectors.length; i++ ) {
|
141
|
+
|
142
|
+
// Construct coordinate object
|
143
|
+
var coordinate = {
|
144
|
+
elem : selectors[ i ],
|
145
|
+
offset : fromTop( selectors[ i ] )
|
146
|
+
};
|
147
|
+
|
148
|
+
// And update coordinates array
|
149
|
+
coordinates[ i ] = coordinate;
|
150
|
+
|
151
|
+
}
|
152
|
+
|
153
|
+
}
|
154
|
+
|
155
|
+
// Scroll handler function
|
156
|
+
function scrollHandler() {
|
157
|
+
|
158
|
+
// Scoped variables
|
159
|
+
var newScrollY = window.pageYOffset,
|
160
|
+
rockBottom = newScrollY < 0 || newScrollY + winHeight >= docHeight,
|
161
|
+
newActiveItem,
|
162
|
+
activeLink,
|
163
|
+
landmark;
|
164
|
+
|
165
|
+
// Loop through coordinates
|
166
|
+
for ( var i = 0; i < coordinates.length; i++ ) {
|
167
|
+
|
168
|
+
// Scoped variables
|
169
|
+
var firstWaypoint = coordinates[ 0 ],
|
170
|
+
currWaypoint = coordinates[ i ],
|
171
|
+
nextWaypoint = coordinates[ i + 1 ],
|
172
|
+
lastWaypoint = coordinates[ coordinates.length - 1 ];
|
173
|
+
|
174
|
+
// If scrolled to last waypoint
|
175
|
+
if ( newScrollY < firstWaypoint.offset ) {
|
176
|
+
|
177
|
+
// Set active item to first waypoint
|
178
|
+
newActiveItem = firstWaypoint.elem.id;
|
179
|
+
|
180
|
+
// If scrolled to bottom of page or on past the last waypoint
|
181
|
+
} else if ( rockBottom || newScrollY > lastWaypoint.offset - options.elemOffset ) {
|
182
|
+
|
183
|
+
// Set active item to last waypoint
|
184
|
+
newActiveItem = lastWaypoint.elem.id;
|
185
|
+
|
186
|
+
// Otherwise if a waypoint is in the viewport
|
187
|
+
} else if ( newScrollY > currWaypoint.offset - options.elemOffset && newScrollY < nextWaypoint.offset - options.elemOffset ) {
|
188
|
+
|
189
|
+
// Update active item to match
|
190
|
+
newActiveItem = currWaypoint.elem.id;
|
191
|
+
|
192
|
+
}
|
193
|
+
|
194
|
+
}
|
195
|
+
|
196
|
+
// If active item exists
|
197
|
+
if ( newActiveItem ) {
|
198
|
+
|
199
|
+
// Only run when new active item is triggered
|
200
|
+
if ( newActiveItem === oldActiveItem ) return false;
|
201
|
+
|
202
|
+
// Update active link
|
203
|
+
activeLink = navigation.querySelector( 'a[href="#' + newActiveItem + '"]' );
|
204
|
+
|
205
|
+
// If no active link is found, abort
|
206
|
+
if ( !activeLink ) return false;
|
207
|
+
|
208
|
+
// And enable navigation item
|
209
|
+
activate( navigation, activeLink, options.activeAnchor );
|
210
|
+
|
211
|
+
// If landmarks are turned on
|
212
|
+
if ( options.showLandmarks === true ) {
|
213
|
+
|
214
|
+
// Set active landmark to active link’s parent
|
215
|
+
landmark = getClosest( activeLink, options.landmarkSelector );
|
216
|
+
|
217
|
+
// Enable active landmark
|
218
|
+
activate( navigation, landmark, options.activeLandmark );
|
219
|
+
|
220
|
+
}
|
221
|
+
|
222
|
+
// Update old active item variable
|
223
|
+
oldActiveItem = newActiveItem;
|
224
|
+
|
225
|
+
}
|
226
|
+
|
227
|
+
}
|
228
|
+
|
229
|
+
// Click handler function
|
230
|
+
function clickHandler( event ) {
|
231
|
+
|
232
|
+
// Prevent default behavior
|
233
|
+
event.preventDefault();
|
234
|
+
|
235
|
+
// Matches selector function init
|
236
|
+
if ( matches( event.target, 'a[href^="#"]' ) ) {
|
237
|
+
|
238
|
+
// Travel to clicked target
|
239
|
+
travel( event.target, 'click' );
|
240
|
+
|
241
|
+
}
|
242
|
+
}
|
243
|
+
|
244
|
+
// Hash change handler function
|
245
|
+
function hashHandler() {
|
246
|
+
|
247
|
+
// Only run when a hash is present
|
248
|
+
if ( !window.location.hash ) return false;
|
249
|
+
|
250
|
+
// Find the hash’s relevant navigation item
|
251
|
+
var hashAnchor = document.querySelector( 'a[href="' + window.location.hash + '"]' );
|
252
|
+
|
253
|
+
// And travel to its target
|
254
|
+
travel( hashAnchor, 'hash' );
|
255
|
+
|
256
|
+
}
|
257
|
+
|
258
|
+
// Window scroll travel function
|
259
|
+
function travel( destination, trigger ) {
|
260
|
+
|
261
|
+
// Define scoped variable(s)
|
262
|
+
var targetAnchor = destination.href.split( '#' )[ 1 ],
|
263
|
+
targetElement = document.querySelector( '#' + targetAnchor ),
|
264
|
+
targetOffset,
|
265
|
+
travelTime;
|
266
|
+
|
267
|
+
// If a target element exists
|
268
|
+
if ( targetElement ) {
|
269
|
+
|
270
|
+
// Enable new active navigation item
|
271
|
+
activate( navigation, destination, options.activeAnchor );
|
272
|
+
|
273
|
+
// Loop through coordinates
|
274
|
+
for ( var i = 0; i < coordinates.length; i++ ) {
|
275
|
+
|
276
|
+
// If coordinate element matches target element
|
277
|
+
if ( coordinates[ i ].elem === targetElement ) {
|
278
|
+
|
279
|
+
// Assign its coordinates to target offset variable
|
280
|
+
targetOffset = coordinates[ i ].offset;
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
// If trigger was a click
|
285
|
+
if ( trigger === 'click' ) {
|
286
|
+
|
287
|
+
// Temporarily remove scroll listener function
|
288
|
+
window.removeEventListener( 'optimizedScroll', scrollHandler, false );
|
289
|
+
|
290
|
+
// Update the hash
|
291
|
+
history.pushState( null, '', '#' + targetAnchor );
|
292
|
+
|
293
|
+
// Animate scroll to appropriate element
|
294
|
+
scrollTo( targetOffset - options.elemOffset + 1, function() {
|
295
|
+
|
296
|
+
// Once scroll is complete, enable scroll listener
|
297
|
+
window.addEventListener( 'optimizedScroll', scrollHandler, false );
|
298
|
+
|
299
|
+
});
|
300
|
+
|
301
|
+
// Otherwise if trigger was a hash
|
302
|
+
} else if ( trigger === 'hash' ) {
|
303
|
+
|
304
|
+
// Skip the scroll animation
|
305
|
+
window.scrollTo( 0, targetOffset - options.elemOffset + 1 );
|
306
|
+
|
307
|
+
}
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
// Link activation function
|
312
|
+
function activate( container, selector, cls ) {
|
313
|
+
|
314
|
+
// Find currently active link
|
315
|
+
var activeLink = container.querySelector( '.' + cls );
|
316
|
+
|
317
|
+
// And if it exists, disable it
|
318
|
+
if ( activeLink ) activeLink.classList.remove( cls );
|
319
|
+
|
320
|
+
// Then enable the passed selector
|
321
|
+
selector.classList.add( cls );
|
322
|
+
|
323
|
+
}
|
324
|
+
|
325
|
+
};
|
326
|
+
|
327
|
+
// Public API
|
328
|
+
module.exports = waypoints;
|