Skip to content

Instantly share code, notes, and snippets.

@nfq
Created March 7, 2016 11:51
Show Gist options
  • Save nfq/1e1c2a4d1f66e2446e8e to your computer and use it in GitHub Desktop.
Save nfq/1e1c2a4d1f66e2446e8e to your computer and use it in GitHub Desktop.
stroll.js
/*!
* Stroll v1.0.0: Scroll progress bar and anchor points
* (c) 2016 Nathan Querido
* MIT License
* http://github.com/nfq/stroll
*/
(function (root, factory) {
if ( typeof define === 'function' && define.amd ) {
define([], factory(root));
} else if ( typeof exports === 'object' ) {
module.exports = factory(root);
} else {
root.stroll = factory(root);
}
})(typeof global !== 'undefined' ? global : this.window || this.global, function (root) {
//'use strict';
//
// Variables
//
var stroll = {}; // Object for public APIs
var supports = 'querySelector' in document && 'addEventListener' in root && 'classList' in document.createElement('_'); // Feature test
var settings;
// Default settings
var defaults = {
wrapper: '.progress_indicator',
progress: '.progress_bar',
highlight: '.progress_bar_highlight',
position: 'right',
section: "section",
pagination: true,
initClass: 'js-stroll',
callback: function () {}
};
//
// Methods
//
/**
* A simple forEach() implementation for Arrays, Objects and NodeLists.
* @private
* @author Todd Motto
* @link https://github.com/toddmotto/foreach
* @param {Array|Object|NodeList} collection Collection of items to iterate
* @param {Function} callback Callback function for each iteration
* @param {Array|Object|NodeList} scope Object/NodeList/Array that forEach is iterating over (aka `this`)
*/
var forEach = function ( collection, callback, scope ) {
if ( Object.prototype.toString.call( collection ) === '[object Object]' ) {
for ( var prop in collection ) {
if ( Object.prototype.hasOwnProperty.call( collection, prop ) ) {
callback.call( scope, collection[prop], prop, collection );
}
}
} else {
for ( var i = 0, len = collection.length; i < len; i++ ) {
callback.call( scope, collection[i], i, collection );
}
}
};
/**
* Merge two or more objects. Returns a new object.
* @private
* @param {Boolean} deep If true, do a deep (or recursive) merge [optional]
* @param {Object} objects The objects to merge together
* @returns {Object} Merged values of defaults and options
*/
var extend = function () {
// Variables
var extended = {};
var deep = false;
var i = 0;
var length = arguments.length;
// Check if a deep merge
if ( Object.prototype.toString.call( arguments[0] ) === '[object Boolean]' ) {
deep = arguments[0];
i++;
}
// Merge the object into the extended object
var merge = function (obj) {
for ( var prop in obj ) {
if ( Object.prototype.hasOwnProperty.call( obj, prop ) ) {
// If deep merge and property is an object, merge properties
if ( deep && Object.prototype.toString.call(obj[prop]) === '[object Object]' ) {
extended[prop] = extend( true, extended[prop], obj[prop] );
} else {
extended[prop] = obj[prop];
}
}
}
};
// Loop through each object and conduct a merge
for ( ; i < length; i++ ) {
var obj = arguments[i];
merge(obj);
}
return extended;
};
/**
* Create DOM elements which graphically represent the progress
* @method _createElements
* @private
*/
var _createElements = function () {
var wrapper = document.querySelector( settings.wrapper );
var progress = document.querySelector( settings.progress );
var highlight = document.querySelector( settings.highlight );
progress = document.createElement('div');
highlight = document.createElement('div');
progress.classList.add( settings.progress );
highlight.classList.add( settings.highlight );
progress.appendChild( highlight );
wrapper.appendChild( progress );
// Progress bar highlight
// A links
// Dots
// Labels
};
/** Set styles on DOM elements
* @method _elementStyles
* @private
*/
var _elementStyles = function () {
};
/** Section dots
* @method _sectionDots
* @private
*/
var _sectionDots = function () {
var body = document.body;
var sections = document.querySelectorAll( settings.section );
var item = JSON.parse(this.getAttribute('data-stroll'));
paginationList = "";
// Get all sections
for( var i = 0; i < sections.length; i++){
sections[i].dataset.index = i + 1;
if(settings.pagination == true) {
paginationList += "<li><a data-index='" + (i + 1) + "' href='#" + (item.id) + "' data-scroll><span class=\"dot\"></span><span class=\"label\">"+ (item.label) +"</span></a></li>";
}
}
// This should go in _createElements
if(settings.pagination == true) {
var pagination = document.createElement("nav");
pagination.setAttribute("class", "progress_indicator");
body.appendChild(pagination);
pagination.innerHTML = paginationList;
//var posTop = (document.querySelector(".onepage-pagination").offsetHeight / 2) * -1;
//document.querySelector(".onepage-pagination").style.marginTop = posTop;
}
};
/**
* Scroll method
* @method _scrollMethod
* @private
*/
var _scrollMethod = function () {
var body = document.body;
var highlight = document.querySelector( settings.highlight );
if (body.scrollTop) {
percent = (body.scrollTop/(body.scrollHeight - document.documentElement.clientHeight))*100 + '%';
} else {
percent = (window.pageYOffset/(body.scrollHeight - document.documentElement.clientHeight))*100 + '%';
}
if (settings.position === 'top' || settings.position === 'bottom') {
highlight.style.width = percent;
}
if (settings.position === 'left' || settings.position === 'right') {
highlight.style.height = percent;
}
};
/**
* Handle scroll event methods
* @method _eventHandler
* @private
*/
var _eventHandler = function ( event ) {
if ( event.type === 'scroll' ) {
_scrollMethod();
}
};
/**
* Destroy the current initialization.
* @public
*/
stroll.destroy = function () {
// If plugin isn't already initialized, stop
if ( !settings ) return;
document.documentElement.classList.remove( settings.initClass );
// Remove event listeners
document.removeEventListener('scroll', _eventHandler, false);
// Reset variables
settings = null;
};
/**
* Initialize Stroll
* @public
* @param {Object} options User settings
*/
stroll.init = function ( options ) {
// Feature test
if ( !supports ) return;
// Destroy any existing initializations
stroll.destroy();
// Merge user options with defaults
settings = extend( defaults, options || {} ); // Merge user options with defaults
//_createElements();
_sectionDots();
// Add class to HTML element to activate conditional CSS
document.documentElement.classList.add( settings.initClass );
// Listen for scroll events and run event handler
document.addEventListener('scroll', _eventHandler, false);
};
//
// Public APIs
//
return stroll;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment