Follow

by levchenko_d

HTML

<script src="https://beat.today/javascripts/functions.js"></script>
<div class="result">No Match</div>

<ul>
<li class="follow" data-follow="1"><span>1</span></li>
  <li class="follow" data-follow="2"><span>2</span></li>
  <li class="follow" data-follow="3"><span>3</span></li>
  <li class="follow" data-follow="4"><span>4</span></li>
  <li class="follow" data-follow="5"><span>5</span></li>
  <li class="follow" data-follow="6"><span>6</span></li>
  <li class="follow" data-follow="7"><span>7</span></li>
  <li class="follow" data-follow="8"><span>8</span></li>
  <li class="follow" data-follow="9"><span>9</span></li>
  <li class="follow" data-follow="10"><span>10</span></li>
  <li class="follow" data-follow="11"><span>11</span></li>
</ul>

CSS

li{
  display: block;
  height: 300px;
  background: silver;
  margin: 0;
  border-bottom:solid 1px black;
}

.follow span{
  line-height: 300px;
  display: block;
  text-align: center;
  color: #fff;
  font-size: 36px;
}

.follow-match{
  background: blue;
}

.result{
  position: fixed;
  width: 200px;
  height: 29px;
  border-radius: 0 0 10px 10px;
  background: white;
  top:0;
  left: 0;
  right: 0;
  margin: auto;
  text-align: center;
}

JavaScript

/*
	Follow usage:
  
  var followList = new Follow({
  	selector: '.follow',//default
    onEnter: function(element){
    	// your stuff here...
    },
		onLeave: function(element){
    	// your stuff here...
    },
    onNoMatch: function(previousMatch){
    	// your stuff here...
    }
  });

*/

var Follow = function(options){
	var t = this;
  
  t.o = {};
  t.o.selector = options.selector || '.follow';
  t.o.followingClass = options.followingClass || 'following';
	t.o.matchClass = options.matchClass || 'follow-match';
  
  t.o.onEnter = App.isFn(options.onEnter) || options.onEnter;
  t.o.onLeave = App.isFn(options.onLeave) || options.onLeave;
  t.o.onNoMatch = App.isFn(options.onNoMatch) || options.onNoMatch;
  
  t.elementDOMs = App.qa(t.o.selector);
  t.scrollTop = App.getScrollTop(document.body);
  
  t.previousElement = null;
  t.onScroll = null;
  t.onResize = null;
  
  t.init();
};

Follow.prototype.getBounds = function(){
	var t=this;
  
  function getElementBounds(element, index){
  	var topBound = element.position().y,
    		bottomBound = topBound + element.size().y;
        
  	element.followData = {
    	bounds : {
        top: topBound,
        bottom: bottomBound
    	}
    };
    
    element.addClass(t.o.followingClass);
  }
  
  t.elementDOMs.loop(getElementBounds);
};

Follow.prototype.findMatchingBounds = function(callback){
	var t=this,
  		i = 0,
      match = null,
      elementsSize = t.elementDOMs.length;
  
  function isMatch(element){
  	var isTopSmaller = element.followData.bounds.top <= t.scrollTop,
    		isBottomBigger = element.followData.bounds.bottom >= t.scrollTop;
        
    return isTopSmaller && isBottomBigger;
  }
  
  do {
    if(i === elementsSize){//if no match
    	callback(null);
    } else {
			var element = t.elementDOMs[i];
      if(isMatch(element)){
      	match = element;
      	callback(element);
      } else {
      	element.removeClass(t.o.matchClass);
      }
    }
  	i++;
  } while (!match &&...