Visible elements in a scrollable area (pure JavaScript)

by rplantiko

HTML

<div id="container" class='list'>
    <table>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>
        <tr>
            <td>item</td>
        </tr>        
    </table>
</div>

<div>
Fully enclosed rows:  <input id="result" type="text" size="30">
</div>

CSS

.list {
    height: 112px;
    width: 300px;
    display: block;
    overflow-y: scroll;
    margin-bottom:1em;
}
table tr td {
    width: 300px;
    height: 50px;
    background-color: red;
    border: 1px solid #000;
}

JavaScript

(function(){
    
    var result = document.getElementById("result");
    var container = document.getElementById("container");
    var cells  = toArray(
       document.getElementsByTagName("td")
       );
    var isCellVisible = isChildElementVisible( container );
    
    container.addEventListener("scroll",determineVisibleRows);
    determineVisibleRows();
    
    function determineVisibleRows() {
      result.value =  
        cells.filter( isCellVisible ).map( rowIndex ).join(',');
      }

    function isChildElementVisible(container) {
      var containerHeight = parseInt(getComputedStyle(container).height);
      return function(element) {
        var containerTop = parseInt( container.scrollTop );
        var containerBottom = containerTop + containerHeight;
        var elemTop = element.offsetTop;
        var elemHeight =  parseInt(getComputedStyle(element).height);
        var elemBottom = elemTop + elemHeight;
        return (elemTop >= containerTop && 
                elemBottom <= containerBottom);
        }
     }

    function toArray(arraylikeObject) {
      return Array.prototype.slice.call( arraylikeObject, 0 )
    }
    
    function rowIndex( cell ) {
      return cell.parentNode.rowIndex+1;  
    }
    
})()