/** * @preserve ScrollStory - v1.1.0 - 2018-09-20 * https://github.com/sjwilliams/scrollstory * Copyright (c) 2017 Josh Williams; Licensed MIT */ (function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory)}else{factory(jQuery)}})(function($,undefined){var pluginName="scrollStory";var eventNameSpace="."+pluginName;var defaults={content:null,contentSelector:".story",keyboard:true,scrollOffset:0,triggerOffset:0,scrollEvent:"scroll",autoActivateFirstItem:false,disablePastLastItem:true,speed:800,easing:"swing",throttleType:"throttle",scrollSensitivity:100,throttleTypeOptions:null,autoUpdateOffsets:true,debug:false,enabled:true,setup:$.noop,destroy:$.noop,itembuild:$.noop,itemfocus:$.noop,itemblur:$.noop,itemfilter:$.noop,itemunfilter:$.noop,itementerviewport:$.noop,itemexitviewport:$.noop,categoryfocus:$.noop,categeryblur:$.noop,containeractive:$.noop,containerinactive:$.noop,containerresize:$.noop,containerscroll:$.noop,updateoffsets:$.noop,triggeroffsetupdate:$.noop,scrolloffsetupdate:$.noop,complete:$.noop};var instanceCounter=0;var dateNow=Date.now||function(){return(new Date).getTime()};var debounce=function(func,wait,immediate){var result;var timeout=null;return function(){var context=this,args=arguments;var later=function(){timeout=null;if(!immediate){result=func.apply(context,args)}};var callNow=immediate&&!timeout;clearTimeout(timeout);timeout=setTimeout(later,wait);if(callNow){result=func.apply(context,args)}return result}};var throttle=function(func,wait,options){var context,args,result;var timeout=null;var previous=0;options||(options={});var later=function(){previous=options.leading===false?0:dateNow();timeout=null;result=func.apply(context,args)};return function(){var now=dateNow();if(!previous&&options.leading===false){previous=now}var remaining=wait-(now-previous);context=this;args=arguments;if(remaining<=0){clearTimeout(timeout);timeout=null;previous=now;result=func.apply(context,args)}else if(!timeout&&options.trailing!==false){timeout=setTimeout(later,remaining)}return result}};var $window=$(window);var winHeight=$window.height();var offsetToPx=function(offset){var pxOffset;if(offsetIsAPercentage(offset)){pxOffset=offset.slice(0,-1);pxOffset=Math.round(winHeight*(parseInt(pxOffset,10)/100))}else{pxOffset=parseInt(offset,10)}return pxOffset};var offsetIsAPercentage=function(offset){return typeof offset==="string"&&offset.slice(-1)==="%"};function ScrollStory(element,options){this.el=element;this.$el=$(element);this.options=$.extend({},defaults,options);this.useNativeScroll=typeof this.options.scrollEvent==="string"&&this.options.scrollEvent.indexOf("scroll")===0;this._defaults=defaults;this._name=pluginName;this._instanceId=function(){return pluginName+"_"+instanceCounter}();this.init()}ScrollStory.prototype={init:function(){this._items=[];this._itemsById={};this._categories=[];this._tags=[];this._isActive=false;this._activeItem;this._previousItems=[];this.$el.on("setup"+eventNameSpace,this._onSetup.bind(this));this.$el.on("destroy"+eventNameSpace,this._onDestroy.bind(this));this.$el.on("containeractive"+eventNameSpace,this._onContainerActive.bind(this));this.$el.on("containerinactive"+eventNameSpace,this._onContainerInactive.bind(this));this.$el.on("itemblur"+eventNameSpace,this._onItemBlur.bind(this));this.$el.on("itemfocus"+eventNameSpace,this._onItemFocus.bind(this));this.$el.on("itementerviewport"+eventNameSpace,this._onItemEnterViewport.bind(this));this.$el.on("itemexitviewport"+eventNameSpace,this._onItemExitViewport.bind(this));this.$el.on("itemfilter"+eventNameSpace,this._onItemFilter.bind(this));this.$el.on("itemunfilter"+eventNameSpace,this._onItemUnfilter.bind(this));this.$el.on("categoryfocus"+eventNameSpace,this._onCategoryFocus.bind(this));this.$el.on("triggeroffsetupdate"+eventNameSpace,this._onTriggerOffsetUpdate.bind(this));this._trigger("setup",null,this);this.addItems(this.options.content,{handleRepaint:false});this.updateOffsets();this._trigger("complete",null,this);if(this.options.enabled){this._handleRepaint()}if(this.options.keyboard){$(document).keydown(function(e){var captured=true;switch(e.keyCode){case 37:if(e.metaKey){return}this.previous();break;case 39:this.next();break;default:captured=false}return!captured}.bind(this))}this.$trigger=$('
').css({position:"fixed",width:"100%",height:"1px",top:offsetToPx(this.options.triggerOffset)+"px",left:"0px",backgroundColor:"#ff0000","-webkit-transform":"translateZ(0)","-webkit-backface-visibility":"hidden",zIndex:1e3}).attr("id",pluginName+"Trigger-"+this._instanceId);if(this.options.debug){this.$trigger.appendTo("body")}var scrollThrottle,scrollHandler;if(this.useNativeScroll){scrollThrottle=this.options.throttleType==="throttle"?throttle:debounce;scrollHandler=scrollThrottle(this._handleScroll.bind(this),this.options.scrollSensitivity,this.options.throttleTypeOptions);$window.on("scroll"+eventNameSpace,scrollHandler)}else{scrollHandler=this._handleScroll.bind(this);if(typeof this.options.scrollEvent==="function"){this.options.scrollEvent(scrollHandler)}else{$window.on(this.options.scrollEvent+eventNameSpace,function(){scrollHandler()})}}var resizeThrottle=debounce(this._handleResize,100);$window.on("DOMContentLoaded"+eventNameSpace+" load"+eventNameSpace+" resize"+eventNameSpace,resizeThrottle.bind(this));instanceCounter=instanceCounter+1},index:function(index,callback){if(typeof index==="number"&&this.getItemByIndex(index)){this.setActiveItem(this.getItemByIndex(index),{},callback)}else{return this.getActiveItem().index}},next:function(_index){var currentIndex=_index||this.index();var nextItem;if(typeof currentIndex==="number"){nextItem=this.getItemByIndex(currentIndex+1);if(nextItem){if(!nextItem.filtered){this.index(currentIndex+1)}else{this.next(currentIndex+1)}}}},previous:function(_index){var currentIndex=_index||this.index();var previousItem;if(typeof currentIndex==="number"){previousItem=this.getItemByIndex(currentIndex-1);if(previousItem){if(!previousItem.filtered){this.index(currentIndex-1)}else{this.previous(currentIndex-1)}}}},getActiveItem:function(){return this._activeItem},setActiveItem:function(item,options,callback){options=options||{};if(item.id&&this.getItemById(item.id)){this._scrollToItem(item,options,callback)}},each:function(callback){this.applyToAllItems(callback)},getLength:function(){return this.getItems().length},getItems:function(){return this._items},getItemById:function(id){return this._itemsById[id]},getItemByIndex:function(index){return this._items[index]},getItemsBy:function(truthTest){if(typeof truthTest!=="function"){throw new Error("You must provide a truthTest function")}return this.getItems().filter(function(item){return truthTest(item)})},getItemsWhere:function(properties){var keys,items=[];if($.isPlainObject(properties)){keys=Object.keys(properties);items=this.getItemsBy(function(item){var isMatch=keys.every(function(key){var match;if(typeof properties[key]==="function"){match=properties[key](item[key]);if(typeof match!=="boolean"){match=item[key]===match}}else{match=item[key]===properties[key]}return match});if(isMatch){return item}})}return items},getItemsInViewport:function(){return this.getItemsWhere({inViewport:true})},getPreviousItem:function(){return this._previousItems[0]},getPreviousItems:function(){return this._previousItems},getPercentScrollToLastItem:function(){return this._percentScrollToLastItem||0},getScrollComplete:function(){return this._totalScrollComplete||0},getFilteredItems:function(){return this.getItemsWhere({filtered:true})},getUnFilteredItems:function(){return this.getItemsWhere({filtered:false})},getItemsByCategory:function(categorySlug){return this.getItemsWhere({category:categorySlug})},getCategorySlugs:function(){return this._categories},filter:function(item){if(!item.filtered){item.filtered=true;this._trigger("itemfilter",null,item)}},unfilter:function(item){if(item.filtered){item.filtered=false;this._trigger("itemunfilter",null,item)}},filterAll:function(callback){callback=$.isFunction(callback)?callback.bind(this):$.noop;var filterFnc=this.filter.bind(this);this.getItems().forEach(filterFnc)},unfilterAll:function(callback){callback=$.isFunction(callback)?callback.bind(this):$.noop;var unfilterFnc=this.unfilter.bind(this);this.getItems().forEach(unfilterFnc)},filterBy:function(truthTest,callback){callback=$.isFunction(callback)?callback.bind(this):$.noop;var filterFnc=this.filter.bind(this);this.getItemsBy(truthTest).forEach(filterFnc);callback()},filterWhere:function(properties,callback){callback=$.isFunction(callback)?callback.bind(this):$.noop;var filterFnc=this.filter.bind(this);this.getItemsWhere(properties).forEach(filterFnc);callback()},isContainerActive:function(){return this._isActive},disable:function(){this.options.enabled=false},enable:function(){this.options.enabled=true},updateTriggerOffset:function(offset){this.options.triggerOffset=offset;this.updateOffsets();this._trigger("triggeroffsetupdate",null,offsetToPx(offset))},updateScrollOffset:function(offset){this.options.scrollOffset=offset;this.updateOffsets();this._trigger("scrolloffsetupdate",null,offsetToPx(offset))},_setActiveItem:function(){var containerInActiveArea=this._distanceToFirstItemTopOffset<=0&&Math.abs(this._distanceToOffset)-this._height<0;var items=this.getItemsWhere({filtered:false});var activeItem;items.forEach(function(item){if(item.adjustedDistanceToOffset<=0){if(!activeItem){activeItem=item}else{if(activeItem.adjustedDistanceToOffset0){activeItem=items[0]}if(activeItem){this._focusItem(activeItem);if(!this._isActive){this._isActive=true;this._trigger("containeractive")}}else{this._blurAllItems();if(this._isActive){this._isActive=false;this._trigger("containerinactive")}}},_scrollToItem:function(item,opts,callback){callback=$.isFunction(callback)?callback.bind(this):$.noop;opts=$.extend(true,{scrollOffset:item.scrollOffset!==false?offsetToPx(item.scrollOffset):offsetToPx(this.options.scrollOffset),speed:this.options.speed,easing:this.options.easing},opts);var debouncedCallback=debounce(callback,100);var scrolllTop=item.el.offset().top-offsetToPx(opts.scrollOffset);$("html, body").stop(true).animate({scrollTop:scrolllTop},opts.speed,opts.easing,debouncedCallback)},applyToAllItems:function(callback,exceptions){exceptions=$.isArray(exceptions)?exceptions:[exceptions];callback=$.isFunction(callback)?callback.bind(this):$.noop;var items=this.getItems();var i=0;var length=items.length;var item;for(i=0;i=0){item.percentScrollComplete=0}else if(Math.abs(item.distanceToOffset)>=rect.height){item.percentScrollComplete=1}else{item.percentScrollComplete=Math.abs(item.distanceToOffset)/rect.height}totalScrollComplete=totalScrollComplete+item.percentScrollComplete;previouslyInViewport=item.inViewport;item.inViewport=rect.bottom>0&&rect.right>0&&rect.left=0&&rect.left>=0&&rect.bottom<=wHeight&&rect.right<=wWidth;if(item.inViewport&&!previouslyInViewport){this._trigger("itementerviewport",null,item)}else if(!item.inViewport&&previouslyInViewport){this._trigger("itemexitviewport",null,item)}}this._distanceToFirstItemTopOffset=items[0].adjustedDistanceToOffset;this._distanceToOffset=this._topOffset-scrollTop-triggerOffset;var percentScrollToLastItem=0;if(this._distanceToOffset<0){percentScrollToLastItem=1-lastItem.distanceToOffset/(this._height-lastItem.height);percentScrollToLastItem=percentScrollToLastItem<1?percentScrollToLastItem:1}this._percentScrollToLastItem=percentScrollToLastItem;this._totalScrollComplete=totalScrollComplete/length},addItems:function(items,opts){opts=$.extend(true,{handleRepaint:true},opts);if(items instanceof $){this._prepItemsFromSelection(items)}else if(typeof items==="string"){this._prepItemsFromSelection(this.$el.find(items))}else if($.isArray(items)){this._prepItemsFromData(items)}else{this._prepItemsFromSelection(this.$el.find(this.options.contentSelector))}if(this.getItems().length<1){throw new Error("addItems found no valid items.")}if(opts.handleRepaint){this._handleRepaint()}},destroy:function(removeMarkup){removeMarkup=removeMarkup||false;if(removeMarkup){this.each(function(item){item.el.remove()})}this._trigger("destroy");var containerData=this.$el.data();containerData["plugin_"+pluginName]=null},_handleRepaint:function(updateOffsets){updateOffsets=updateOffsets===false?false:true;if(updateOffsets){this.updateOffsets()}this._updateScrollPositions();this._setActiveItem()},_handleScroll:function(){if(this.options.enabled){this._handleRepaint(false);this._trigger("containerscroll")}},_handleResize:function(){winHeight=$window.height();if(this.options.enabled&&this.options.autoUpdateOffsets){if(offsetIsAPercentage(this.options.triggerOffset)){this.updateTriggerOffset(this.options.triggerOffset)}if(offsetIsAPercentage(this.options.scrollOffset)){this.updateScrollOffset(this.options.scrollOffset)}this._debouncedHandleRepaint();this._trigger("containerresize")}},_onSetup:function(){this.$el.addClass(pluginName)},_onDestroy:function(){this.$el.off(eventNameSpace);$window.off(eventNameSpace);var itemClassesToRemove=["scrollStoryItem","inviewport","active","filtered"].join(" ");this.each(function(item){item.el.removeClass(itemClassesToRemove)});this.$el.removeClass(function(i,classNames){var classNamesToRemove=[];classNames.split(" ").forEach(function(c){if(c.lastIndexOf(pluginName)===0){classNamesToRemove.push(c)}});return classNamesToRemove.join(" ")});this.$trigger.remove()},_onContainerActive:function(){this.$el.addClass(pluginName+"Active")},_onContainerInactive:function(){this.$el.removeClass(pluginName+"Active")},_onItemFocus:function(ev,item){item.el.addClass("active");this._manageContainerClasses("scrollStoryActiveItem-",item.id);if(item.category){if(this.getPreviousItem()&&this.getPreviousItem().category!==item.category||!this.isContainerActive()){this._trigger("categoryfocus",null,item.category);if(this.getPreviousItem()){this._trigger("categoryblur",null,this.getPreviousItem().category)}}}},_onItemBlur:function(ev,item){this._previousItems.unshift(item);item.el.removeClass("active")},_onItemEnterViewport:function(ev,item){item.el.addClass("inviewport")},_onItemExitViewport:function(ev,item){item.el.removeClass("inviewport")},_onItemFilter:function(ev,item){item.el.addClass("filtered");if(this.options.autoUpdateOffsets){this._debouncedHandleRepaint()}},_onItemUnfilter:function(ev,item){item.el.removeClass("filtered");if(this.options.autoUpdateOffsets){this._debouncedHandleRepaint()}},_onCategoryFocus:function(ev,category){this._manageContainerClasses("scrollStoryActiveCategory-",category)},_onTriggerOffsetUpdate:function(ev,offset){this.$trigger.css({top:offset+"px"})},_manageContainerClasses:function(prefix,value){this.$el.removeClass(function(index,classes){return classes.split(" ").filter(function(c){return c.lastIndexOf(prefix,0)===0}).join(" ")});this.$el.addClass(prefix+value)},_prepItemsFromSelection:function($selection){var that=this;$selection.each(function(){that._addItem({},$(this))})},_prepItemsFromData:function(items){var that=this;var selector=this.options.contentSelector.replace(/\./g,"");var frag=document.createDocumentFragment();items.forEach(function(data){var $item=$('
');that._addItem(data,$item);frag.appendChild($item.get(0))});this.$el.append(frag)},_addItem:function(data,$el){var domData=$el.data();var item={index:this._items.length,el:$el,id:$el.attr("id")?$el.attr("id"):data.id?data.id:"story"+instanceCounter+"-"+this._items.length,data:$.extend({},data,domData),category:domData.category||data.category,tags:data.tags||[],scrollStory:this,active:false,filtered:false,scrollOffset:false,triggerOffset:false,inViewport:false};if(!$el.attr("id")){$el.attr("id",item.id)}$el.addClass("scrollStoryItem");this._items.push(item);this._itemsById[item.id]=item;this._trigger("itembuild",null,item);if(item.category&&this._categories.indexOf(item.category)===-1){this._categories.push(item.category)}},_trigger:function(eventType,event,data){var callback=this.options[eventType];var prop,orig;if($.isFunction(callback)){data=data||{};event=$.Event(event);event.target=this.el;event.type=eventType;orig=event.originalEvent;if(orig){for(prop in orig){if(!(prop in event)){event[prop]=orig[prop]}}}this.$el.trigger(event,data);var boundCb=this.options[eventType].bind(this);boundCb(event,data)}}};ScrollStory.prototype.debouncedUpdateOffsets=debounce(ScrollStory.prototype.updateOffsets,100);ScrollStory.prototype._debouncedHandleRepaint=debounce(ScrollStory.prototype._handleRepaint,100);$.fn[pluginName]=function(options){return this.each(function(){if(!$.data(this,"plugin_"+pluginName)){$.data(this,"plugin_"+pluginName,new ScrollStory(this,options))}})}});