nav-scroll-spy
Advanced tools
Comparing version
@@ -12,2 +12,3 @@ 'use strict'; | ||
babelify = require('babelify'), | ||
babel = require('gulp-babel'), | ||
pug = require('gulp-pug'), | ||
@@ -45,4 +46,14 @@ uglify = require('gulp-uglify'); | ||
// Lib folder with module | ||
gulp.task('bundle-js', () => { | ||
return gulp.src([src + 'js/nav-scroll-spy.js', src + 'js/throttle.js']) | ||
.pipe(babel({ | ||
presets: ['es2015'] | ||
})) | ||
.pipe(gulp.dest('./lib')) | ||
.pipe(browserSync.stream()); | ||
}); | ||
gulp.task('bundle-js', function() { | ||
// Demo | ||
gulp.task('demo-js', function() { | ||
return browserify(src + 'js/demo.js') | ||
@@ -53,3 +64,3 @@ .transform('babelify', { presets: ['es2015', 'stage-1'] }) | ||
.pipe(buffer()) | ||
// .pipe(uglify()) | ||
.pipe(uglify()) | ||
.pipe(gulp.dest(build + 'js/')) | ||
@@ -69,6 +80,6 @@ .pipe(browserSync.stream()); | ||
gulp.watch([src + 'pug/**/*.pug', src + 'pug/includes/*.pug'], gulp.series('pug')); | ||
gulp.watch(src + 'js/**/*.js', gulp.series('bundle-js')); | ||
gulp.watch(src + 'js/**/*.js', gulp.series('demo-js')); | ||
}); | ||
// default | ||
gulp.task('default', gulp.series(gulp.parallel('pug', 'sass', 'bundle-js'), 'watch')); | ||
gulp.task('default', gulp.series(gulp.parallel('pug', 'sass', 'bundle-js', 'demo-js'), 'watch')); |
@@ -1,338 +0,1 @@ | ||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | ||
// Animation function with requestAnimationFrame() | ||
module.exports = function animate( draw, duration ) { | ||
let start = performance.now(); | ||
requestAnimationFrame(function animate( time ) { | ||
let timePassed = time - start; | ||
if (timePassed > duration) timePassed = duration; | ||
draw(timePassed); | ||
if (timePassed < duration) requestAnimationFrame(animate); | ||
}); | ||
}; | ||
},{}],2:[function(require,module,exports){ | ||
let animate = require('./animate.js'); | ||
class scrollToElement { | ||
constructor(options) { | ||
let defaults = { | ||
anchors: 'a[href*="#"]', | ||
duration: 350, | ||
offset: 0, | ||
easing: 'easeInOut' | ||
}; | ||
options ? this.options = Object.assign(defaults, options) : this.options = defaults; | ||
} | ||
setClickEvent() { | ||
let that = this, | ||
anchors = document.querySelectorAll(this.options.anchors); | ||
for( let anchor of anchors ){ | ||
anchor.addEventListener('click', e=> that.clickHandler(e)); | ||
} | ||
} | ||
makeEaseInOut(timing, progress) { | ||
return () => { | ||
if (progress < 0.5) { | ||
return timing(2 * progress) / 2; | ||
} else { | ||
return (2 - timing(2 * (1 - progress))) / 2; | ||
} | ||
}; | ||
} | ||
timingFn(progress, startVal, displace) { | ||
if (this.easing === 'linear') { | ||
return (progress * displace) + startVal; | ||
} else { | ||
// Default animation 'easeInOut' | ||
let easeInOut = this.makeEaseInOut((progress)=> Math.pow(progress, 2), progress); | ||
return (easeInOut() * displace) + startVal; | ||
} | ||
} | ||
clickHandler(e) { | ||
e.preventDefault(); | ||
let el = e.target, | ||
link = el.getAttribute('href'), | ||
elToScroll = document.querySelector(link) || document.querySelector(`*[data-section="${link.substr(1)}"]`), | ||
offsetTop = this.elOffsetTop(elToScroll); | ||
// Animation | ||
let startVal = window.pageYOffset, | ||
endVal = offsetTop + this.options.offset, | ||
displace = endVal - startVal, | ||
duration = this.options.duration; | ||
if (displace === 0) return; | ||
animate((timePassed) => { | ||
let progress = timePassed / duration, | ||
newVal = this.timingFn(progress, startVal, displace); | ||
window.scrollTo(null, newVal); | ||
}, duration); | ||
} | ||
elOffsetTop(el) { | ||
let top = 0; | ||
while (el.parentNode) { | ||
top += el.offsetTop; | ||
el = el.parentNode; | ||
} | ||
return top; | ||
} | ||
init() { | ||
this.setClickEvent(); | ||
} | ||
} | ||
module.exports = scrollToElement; | ||
},{"./animate.js":1}],3:[function(require,module,exports){ | ||
'use strict'; | ||
var _scrollWindowToElement = require('scroll-window-to-element'); | ||
var _scrollWindowToElement2 = _interopRequireDefault(_scrollWindowToElement); | ||
var _navScrollSpy = require('./nav-scroll-spy'); | ||
var _navScrollSpy2 = _interopRequireDefault(_navScrollSpy); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var quarterWindowHeight = window.innerHeight / 4; | ||
var spy = new _navScrollSpy2.default({ | ||
offset: quarterWindowHeight | ||
}); | ||
spy.init(); | ||
// Smooth scroll to element | ||
var scroll = new _scrollWindowToElement2.default({ | ||
anchors: '.nav a' | ||
}); | ||
scroll.init(); | ||
},{"./nav-scroll-spy":4,"scroll-window-to-element":2}],4:[function(require,module,exports){ | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _throttle = require('./throttle.js'); | ||
var _throttle2 = _interopRequireDefault(_throttle); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var NavScrollSpy = function () { | ||
function NavScrollSpy(options) { | ||
_classCallCheck(this, NavScrollSpy); | ||
var defaults = { | ||
offset: 0, | ||
currentClass: 'active', | ||
selector: 'nav a', | ||
throttle: 100 | ||
}; | ||
options ? this.options = Object.assign(defaults, options) : this.options = defaults; | ||
this.prevCurrentSections = []; | ||
this.navItems = {}; | ||
} | ||
_createClass(NavScrollSpy, [{ | ||
key: 'elOffsetTop', | ||
value: function elOffsetTop(el) { | ||
var top = 0; | ||
try { | ||
while (el.parentNode) { | ||
top += el.offsetTop; | ||
el = el.parentNode; | ||
} | ||
return top; | ||
} catch (err) { | ||
//#####################=> TODO | ||
console.warn('Section missing!', err); | ||
} | ||
} | ||
}, { | ||
key: 'getElements', | ||
value: function getElements() { | ||
// Nav Items | ||
var navItemsNodeList = document.querySelectorAll(this.options.selector); | ||
// Store nav items in object with hash-keys | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = navItemsNodeList[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var item = _step.value; | ||
this.navItems[item.hash] = item; | ||
} | ||
// Store Sections | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
this.sections = []; | ||
for (var key in this.navItems) { | ||
var section = document.querySelector(key); | ||
this.sections.push(section); | ||
} | ||
} | ||
}, { | ||
key: 'getSectionsParams', | ||
value: function getSectionsParams() { | ||
var _this = this; | ||
this.sectionsParams = []; | ||
this.sections.forEach(function (item, i) { | ||
var top = _this.elOffsetTop(item); | ||
_this.sectionsParams.push({ top: top, bottom: top + item.offsetHeight, id: '#' + item.id }); | ||
}); | ||
} | ||
}, { | ||
key: 'setCurentMenuItems', | ||
value: function setCurentMenuItems(sectionsInScreen) { | ||
var _this2 = this; | ||
// prevCurrentSections not available | ||
if (this.prevCurrentSections.length === 0) { | ||
// No items for cleaning and no new available | ||
if (sectionsInScreen.length === 0) { | ||
return; | ||
} | ||
// No items for cleaning and new available | ||
else { | ||
for (var key in sectionsInScreen) { | ||
var id = sectionsInScreen[key].id; | ||
this.navItems[id].parentNode.classList.add(this.options.currentClass); | ||
} | ||
} | ||
} | ||
// prevCurrentSections available | ||
else { | ||
// Available prevNavItems and new not available. Remove old. ( this.prevCurrentSections.length !== 0 && sectionsInScreen.length === 0 ) | ||
if (sectionsInScreen.length === 0) { | ||
for (var _key in this.prevCurrentSections) { | ||
var _id = this.prevCurrentSections[_key].id; | ||
this.navItems[_id].parentNode.classList.remove(this.options.currentClass); | ||
} | ||
} | ||
// Available prevNavItems and new available, compare they | ||
else { | ||
Object.keys(this.navItems).forEach(function (key, i) { | ||
// Remove current class | ||
if (_this2.prevCurrentSections[i] && !sectionsInScreen[i]) { | ||
_this2.navItems[key].parentNode.classList.remove(_this2.options.currentClass); | ||
} | ||
// Add current class | ||
if (!_this2.prevCurrentSections[i] && sectionsInScreen[i]) { | ||
_this2.navItems[key].parentNode.classList.add(_this2.options.currentClass); | ||
} | ||
// Else available in both arrays and already have current class | ||
}); | ||
} | ||
} | ||
// Store current sections | ||
this.prevCurrentSections = sectionsInScreen; | ||
} | ||
}, { | ||
key: 'defineCurrentSection', | ||
value: function defineCurrentSection() { | ||
var winScrollPos = window.pageYOffset + this.options.offset; | ||
var sectionsInScreen = []; | ||
this.sectionsParams.forEach(function (section, i) { | ||
if (winScrollPos > section.top && winScrollPos < section.bottom) sectionsInScreen[i] = section; | ||
}); | ||
this.setCurentMenuItems(sectionsInScreen); | ||
} | ||
}, { | ||
key: 'setEvents', | ||
value: function setEvents() { | ||
// Throttling to improve performance | ||
var throttledDefineCurrentSection = (0, _throttle2.default)(this.defineCurrentSection, this.options.throttle).bind(this), | ||
throttledGetSectionsParams = (0, _throttle2.default)(this.getSectionsParams, this.options.throttle).bind(this); | ||
// Scroll | ||
window.addEventListener('scroll', function () { | ||
return throttledDefineCurrentSection(); | ||
}); | ||
// Resize | ||
window.addEventListener('resize', function () { | ||
throttledGetSectionsParams(); | ||
throttledDefineCurrentSection(); | ||
}); | ||
} | ||
}, { | ||
key: 'init', | ||
value: function init() { | ||
this.getElements(); | ||
this.getSectionsParams(); | ||
this.setEvents(); | ||
} | ||
}]); | ||
return NavScrollSpy; | ||
}(); | ||
exports.default = NavScrollSpy; | ||
},{"./throttle.js":5}],5:[function(require,module,exports){ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = throttle; | ||
function throttle(func, ms) { | ||
var isThrottled = false, | ||
savedArgs = void 0, | ||
savedThis = void 0; | ||
function wrapper() { | ||
if (isThrottled) { | ||
savedArgs = arguments; | ||
savedThis = this; | ||
return; | ||
} | ||
func.apply(this, arguments); | ||
isThrottled = true; | ||
setTimeout(function () { | ||
isThrottled = false; | ||
if (savedArgs) { | ||
wrapper.apply(savedThis, savedArgs); | ||
savedArgs = savedThis = null; | ||
} | ||
}, ms); | ||
} | ||
return wrapper; | ||
} | ||
},{}]},{},[3]); | ||
!function t(e,n,r){function i(s,a){if(!n[s]){if(!e[s]){var u="function"==typeof require&&require;if(!a&&u)return u(s,!0);if(o)return o(s,!0);var c=new Error("Cannot find module '"+s+"'");throw c.code="MODULE_NOT_FOUND",c}var f=n[s]={exports:{}};e[s][0].call(f.exports,function(t){var n=e[s][1][t];return i(n?n:t)},f,f.exports,t,e,n,r)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s<r.length;s++)i(r[s]);return i}({1:[function(t,e,n){"use strict";e.exports=function(t,e){var n=performance.now();requestAnimationFrame(function r(i){var o=i-n;o>e&&(o=e),t(o),o<e&&requestAnimationFrame(r)})}},{}],2:[function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var i=function(){function t(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(e,n,r){return n&&t(e.prototype,n),r&&t(e,r),e}}(),o=t("./animate.js"),s=function(){function t(e){r(this,t);var n={anchors:'a[href*="#"]',duration:350,offset:0,easing:"easeInOut"};e?this.options=Object.assign(n,e):this.options=n}return i(t,[{key:"setClickEvent",value:function(){var t=this,e=document.querySelectorAll(this.options.anchors),n=!0,r=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(n=(o=s.next()).done);n=!0){var a=o.value;a.addEventListener("click",function(e){return t.clickHandler(e)})}}catch(t){r=!0,i=t}finally{try{!n&&s.return&&s.return()}finally{if(r)throw i}}}},{key:"makeEaseInOut",value:function(t,e){return function(){return e<.5?t(2*e)/2:(2-t(2*(1-e)))/2}}},{key:"timingFn",value:function(t,e,n){if("linear"===this.easing)return t*n+e;var r=this.makeEaseInOut(function(t){return Math.pow(t,2)},t);return r()*n+e}},{key:"clickHandler",value:function(t){var e=this;t.preventDefault();var n=t.target,r=n.getAttribute("href"),i=document.querySelector(r)||document.querySelector('*[data-section="'+r.substr(1)+'"]'),s=this.elOffsetTop(i),a=window.pageYOffset,u=s+this.options.offset,c=u-a,f=this.options.duration;0!==c&&o(function(t){var n=t/f,r=e.timingFn(n,a,c);window.scrollTo(null,r)},f)}},{key:"elOffsetTop",value:function(t){for(var e=0;t.parentNode;)e+=t.offsetTop,t=t.parentNode;return e}},{key:"init",value:function(){this.setClickEvent()}}]),t}();n.default=s,n.scrollToElement=s},{"./animate.js":1}],3:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}var i=t("scroll-window-to-element"),o=r(i),s=t("./nav-scroll-spy"),a=r(s),u=window.innerHeight/4,c=new a.default({offset:u});c.init();var f=new o.default({anchors:".nav a"});f.init()},{"./nav-scroll-spy":4,"scroll-window-to-element":2}],4:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(n,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(e,n,r){return n&&t(e.prototype,n),r&&t(e,r),e}}(),s=t("./throttle.js"),a=r(s),u=function(){function t(e){i(this,t);var n={offset:0,currentClass:"active",selector:'nav a[href*="#"]',throttle:100};e?this.options=Object.assign(n,e):this.options=n,this.prevCurrentSections=[],this.navItems={}}return o(t,[{key:"elOffsetTop",value:function(t){var e=0;try{for(;t.parentNode;)e+=t.offsetTop,t=t.parentNode;return e}catch(t){console.warn("Section missing!",t)}}},{key:"getElements",value:function(){var t=document.querySelectorAll(this.options.selector),e=!0,n=!1,r=void 0;try{for(var i,o=t[Symbol.iterator]();!(e=(i=o.next()).done);e=!0){var s=i.value;this.navItems[s.hash]=s}}catch(t){n=!0,r=t}finally{try{!e&&o.return&&o.return()}finally{if(n)throw r}}this.sections=[];for(var a in this.navItems){var u=document.querySelector(a);this.sections.push(u)}}},{key:"getSectionsParams",value:function(){var t=this;this.sectionsParams=[],this.sections.forEach(function(e,n){var r=t.elOffsetTop(e);t.sectionsParams.push({top:r,bottom:r+e.offsetHeight,id:"#"+e.id})})}},{key:"setCurentMenuItems",value:function(t){var e=this;if(0===this.prevCurrentSections.length){if(0===t.length)return;for(var n in t){var r=t[n].id;this.navItems[r].parentNode.classList.add(this.options.currentClass)}}else if(0===t.length)for(var i in this.prevCurrentSections){var o=this.prevCurrentSections[i].id;this.navItems[o].parentNode.classList.remove(this.options.currentClass)}else Object.keys(this.navItems).forEach(function(n,r){e.prevCurrentSections[r]&&!t[r]&&e.navItems[n].parentNode.classList.remove(e.options.currentClass),!e.prevCurrentSections[r]&&t[r]&&e.navItems[n].parentNode.classList.add(e.options.currentClass)});this.prevCurrentSections=t}},{key:"defineCurrentSection",value:function(){var t=window.pageYOffset+this.options.offset,e=[];this.sectionsParams.forEach(function(n,r){t>n.top&&t<n.bottom&&(e[r]=n)}),this.setCurentMenuItems(e)}},{key:"setEvents",value:function(){var t=(0,a.default)(this.defineCurrentSection,this.options.throttle).bind(this),e=(0,a.default)(this.getSectionsParams,this.options.throttle).bind(this);window.addEventListener("scroll",function(){return t()}),window.addEventListener("resize",function(){e(),t()})}},{key:"init",value:function(){this.getElements(),this.getSectionsParams(),this.setEvents()}}]),t}();n.default=u},{"./throttle.js":5}],5:[function(t,e,n){"use strict";function r(t,e){function n(){return r?(i=arguments,void(o=this)):(t.apply(this,arguments),r=!0,void setTimeout(function(){r=!1,i&&(n.apply(o,i),i=o=null)},e))}var r=!1,i=void 0,o=void 0;return n}Object.defineProperty(n,"__esModule",{value:!0}),n.default=r},{}]},{},[3]); |
{ | ||
"name": "nav-scroll-spy", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "Simple Scroll Spy Class", | ||
"main": "./src/js/nav-scroll-spy.js", | ||
"main": "./lib/nav-scroll-spy.js", | ||
"author": "Vadim Petrov – github.com/komock", | ||
@@ -24,3 +24,3 @@ "repository": { | ||
"gulp-uglify": "^2.0.1", | ||
"scroll-window-to-element": "^1.0.3", | ||
"scroll-window-to-element": "^1.0.4", | ||
"vinyl-buffer": "^1.0.0", | ||
@@ -27,0 +27,0 @@ "vinyl-source-stream": "^1.1.0", |
@@ -33,3 +33,3 @@ # nav-scroll-spy | ||
| currentClass | string | 'active' | Element class for current navigation item (or items). Class will be applied to link parent. | | ||
| selector | string (html) | 'nav a' | Selector for navigation links | | ||
| selector | string (html) | 'nav a[href*="#"]' | Selector for navigation links | | ||
| throttle | number | 100 | Throttling window events (scroll and resize) to improve performance | | ||
@@ -36,0 +36,0 @@ |
@@ -8,3 +8,3 @@ import throttle from './throttle.js'; | ||
currentClass: 'active', | ||
selector: 'nav a', | ||
selector: 'nav a[href*="#"]', | ||
throttle: 100 | ||
@@ -11,0 +11,0 @@ }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
44313
6.25%24
9.09%412
-18.09%2
100%1
Infinity%