src/uki-view/view/dataList.js
function() {
        var range = this._renderingRange();
        if (!range) { return; }

        var packs = this.childViews(),
            fromPX = packs[0] && packs[0].fromPX,
            toPX = packs[0] && packs[packs.length - 1].toPX,
            i, h = range.to - range.from;

        if (packs.length && fromPX <= range.from && toPX >= range.to) {
            // do nothing, everything is rendered as it should
            return;
        } else if (packs.length && fromPX <= range.from) {
            i = 0;
            while (packs[i] && packs[i].toPX < range.from) {
                this.removeChild(packs[i++]);
            }
            packs = packs.slice(i);
            range.from = packs.length ?
                packs[packs.length - 1].toPX : range.from;
            range.to = Math.min(range.from + h, this.metrics().totalHeight());
        } else if (packs.length && toPX >= range.to) {
            i = packs.length - 1;
            while (packs[i] && packs[i].fromPX > range.to) {
                this.removeChild(packs[i--]);
            }
            packs = packs.slice(0, i + 1);
            range.to = packs.length ? packs[0].fromPX : range.to;
            range.from = Math.max(range.to - h, 0);
        } else {
            i = 0;
            while (packs[i]) {
                this.removeChild(packs[i++]);
            }
            packs = [];
        }

        if (range.to > range.from) {
            var rowsRange = this.metrics().rowsForRange(range),
                pack = this._scheduleRenderPack(rowsRange),
                d = this.metrics().rowDimensions(rowsRange.to - 1);

            pack.fromPX = this.metrics().rowDimensions(rowsRange.from).top;
            pack.toPX = d.top + d.height;
            packs.push(pack);

            this._childViews = packs.sort(function(a, b) {
                return a.from - b.from;
            });
        }
    }
function() {
        var range = this._renderingRange();
        if (!range) { return; }

        var packs = this.childViews(),
            fromPX = packs[0] && packs[0].fromPX,
            toPX = packs[0] && packs[packs.length - 1].toPX,
            i, h = range.to - range.from;

        if (packs.length && fromPX <= range.from && toPX >= range.to) {
            // do nothing, everything is rendered as it should
            return;
        } else if (packs.length && fromPX <= range.from) {
            i = 0;
            while (packs[i] && packs[i].toPX < range.from) {
                this.removeChild(packs[i++]);
            }
            packs = packs.slice(i);
            range.from = packs.length ?
                packs[packs.length - 1].toPX : range.from;
            range.to = Math.min(range.from + h, this.metrics().totalHeight());
        } else if (packs.length && toPX >= range.to) {
            i = packs.length - 1;
            while (packs[i] && packs[i].fromPX > range.to) {
                this.removeChild(packs[i--]);
            }
            packs = packs.slice(0, i + 1);
            range.to = packs.length ? packs[0].fromPX : range.to;
            range.from = Math.max(range.to - h, 0);
        } else {
            i = 0;
            while (packs[i]) {
                this.removeChild(packs[i++]);
            }
            packs = [];
        }

        if (range.to > range.from) {
            var rowsRange = this.metrics().rowsForRange(range),
                pack = this._scheduleRenderPack(rowsRange),
                d = this.metrics().rowDimensions(rowsRange.to - 1);

            pack.fromPX = this.metrics().rowDimensions(rowsRange.from).top;
            pack.toPX = d.top + d.height;
            packs.push(pack);

            this._childViews = packs.sort(function(a, b) {
                return a.from - b.from;
            });
        }
    }
Called when visible range or data changes. Renders data in packs.
A pack is:
{ from: 100, to: 200, fromPX: 1000, toPX: 2100, dom: [Element] }
Creates new packs for not yet rendered ranges and removes obsolete
packs.