Skip to content

Instantly share code, notes, and snippets.

@benlumley
Last active December 17, 2015 20:19
Show Gist options
  • Save benlumley/5666699 to your computer and use it in GitHub Desktop.
Save benlumley/5666699 to your computer and use it in GitHub Desktop.
Progress bar JS From http://www.newrepublic.com/
// The progress bar in article titles.
// Only do this on article pages.
if($('#page').hasClass('article')){
$('#title-progress-bar-container').tnrProgressBar({ maxWidthElement: $('#main') });
// The sticky header progress bar.
if($(window).width() == $('#fixed-header').width()){ // iPhone mode is full width.
$('#fixed-header-progress-bar-container').tnrProgressBar({
maxWidthOffset: -3,
maxWidthElement: $(window)
});
} else {
$('#fixed-header-progress-bar-container').tnrProgressBar({
maxWidthOffset: 28,
maxWidthElement: $('#main')
});
}
// If this is a touch environment we'll be using iscroll, so we need to wire up the fixed header
// progress bar to receive its position updated.
callbackDelegates.push($('#fixed-header-progress-bar-container').data('plugin_tnrProgressBar'));
}
/*!
* jQuery lightweight plugin boilerplate
* Original author: @ajpiano
* Further changes, comments: @addyosmani
* Licensed under the MIT license
*/
// the semi-colon before the function invocation is a safety
// net against concatenated scripts and/or other plugins
// that are not closed properly.
;(function ( $, window, document, undefined ) {
// undefined is used here as the undefined global
// variable in ECMAScript 3 and is mutable (i.e. it can
// be changed by someone else). undefined isn't really
// being passed in so we can ensure that its value is
// truly undefined. In ES5, undefined can no longer be
// modified.
// window and document are passed through as local
// variables rather than as globals, because this (slightly)
// quickens the resolution process and can be more
// efficiently minified (especially when both are
// regularly referenced in your plugin).
// Create the defaults once
var tnrProgressBar = 'tnrProgressBar',
defaults = {
window: $(window),
maxWidthOffset: 0
};
// The actual plugin constructor
function TNRProgressBar( element, options ) {
this.element = $(element);
this.manuallyAdjustedScrollPosition = false;
// jQuery has an extend method that merges the
// contents of two or more objects, storing the
// result in the first object. The first object
// is generally empty because we don't want to alter
// the default options for future instances of the plugin
this.options = $.extend( {}, defaults, options) ;
this._defaults = defaults;
this._name = tnrProgressBar;
this._numberPages = 0;
this.init();
}
TNRProgressBar.prototype.init = function () {
// Place initialization logic here
// You already have access to the DOM element and
// the options via the instance, e.g. this.element
// and this.options
// Insert the widget at the bottom.
this.element.append('<span class="progress-bar"></span>');
this._scrollBar = this.element.find('.progress-bar');
this.calculateDimensions();
this.adjustForScroll();
var plugin = this;
var throttledResize = $.throttle(function(){
plugin.calculateDimensions();
plugin.adjustForScroll();
}, 50);
this.options['window'].resize(throttledResize);
// When the font size is updated we need to recalculate things.
this.options['window'].on('font-size-updated', function(e, data){
plugin.calculateDimensions();
plugin.adjustForScroll();
});
var throttledScroll = $.throttle(function(){plugin.adjustForScroll();}, 50);
this.options['window'].scroll(throttledScroll);
};
TNRProgressBar.prototype.updateWithNewScrollPosition = function(newY){
this.manuallyAdjustedScrollPosition = newY;
this.adjustForScroll();
}
// As we scroll we'll adjust the width.
TNRProgressBar.prototype.adjustForScroll = function(){
var p = (this.options['window'].height() + (this.manuallyAdjustedScrollPosition || this.options['window'].scrollTop()))/this._contentHeight;
var width = p * this._scrollBarMaxWidth;
if(width > this._scrollBarMaxWidth - this.options['maxWidthOffset']){
width = this._scrollBarMaxWidth;
}
if(width < 0){
width = 0;
}
if(Modernizr.touch){
// If this is a touch env we'll use a more raw, direct expansion.
this._scrollBar.css({
width: width + 'px'
})
} else { // Otherwise it'll be a little smoother, assuming we have the CPU.
this._scrollBar.stop().animate({
width: width + 'px'
}, 100);
}
}
// Determine how many pages exist, based on screen size and the height of the primary content.
TNRProgressBar.prototype.calculateDimensions = function(){
this._scrollBarMaxWidth = this.options['maxWidthElement'].width() - this.options['maxWidthOffset'];
this._contentHeight = $('.main .primary').offset().top + $('.main .primary').height();
}
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[tnrProgressBar] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + tnrProgressBar)) {
$.data(this, 'plugin_' + tnrProgressBar,
new TNRProgressBar( this, options ));
}
});
}
})( jQuery, window, document );
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment