List View

by HugeHugh

HTML

<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<div class="scrollCon" data-bind="foreach: items">
    <div data-bind="text:index"></div>
</div>
<small>Enter the item number to scroll into view</small>
<input type="text" data-bind="value:targetItem" maxlength="2" size="2"/>
<input type="button" value="scroll" data-bind="click:scrollToItem"/>test

CSS

.scrollCon {
    width: 400px;
    height:300px;
    overflow-y:auto;
    border:1px solid #888;
    border-radius:6px;
    -webkit-overflow-scrolling: touch;
}

.scrollCon > div {
    padding:10px;
    font:14px Arial;
    background:#fdfdd0;
    border-top:2px solid #eee;
    border-bottom:1px solid #888;
}
.scrollCon > div:first-child {
    border-top:none;
}
.scrollCon > div:last-child {
    border-bottom:none;
}

small {
    display:block;
    font-style:italic;
    font-family:Arial;
}

JavaScript

$.expr[':']['isText'] = function(node, index, props){
  return node.innerText === props[3];
}

function itemFactory(index) {
    return {
        index: index
    };
}

function modelFactory(count) {
    var items = [];
    for (var i = 0; i < count; i++) {
        items.push(itemFactory(i+1));
    }
    
    var targetItem = ko.observable(14);
    
    function scrollToItem() {
        var num = parseInt(targetItem()),
            container = $('.scrollCon'),
            target = $('> div:isText("'+num+'")', container),
            tarTop = target.position().top,
            padTop = parseInt(target.css('padding-top')),
            tarHeight = target.height()
                + padTop
                + parseInt(target.css('border-top-width'))
                + parseInt(target.css('border-bottom-width'))
                + 1,
            conHeight = container.height(),
            conScroll = container.scrollTop(),
            minVisible = conHeight - tarHeight;
        
        if (tarTop > minVisible) {
            // scroll the minimum amount down
            container.scrollTop(conScroll + tarTop -  minVisible);
        } else if ((tarTop + tarHeight) < tarHeight) {
            // scroll the minimum amount up
            container.scrollTop(conScroll + tarTop - padTop + 1);
        }
    }
    
    return {
        items: items,
        scrollToItem: scrollToItem,
        targetItem: targetItem
    };
}

var viewModel = modelFactory(30);

ko.applyBindings(viewModel);