ratchet_design 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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;
|