Ember.ListView by @ebryn

by mavilein

HTML

<script src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>
<script src="https://github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.js"></script>
<script type="text/x-handlebars" data-template-name="application" >
    Hello World!
    {{view Ember.ListView contentBinding="App.itemController"
                                    itemViewClassBinding="App.ItemView"
                                    height = 500
                                    rowHeight=50}}
</script>

<script type="text/x-handlebars" data-template-name="item">
    <p>{{index}}, {{open}} </p>
</script>

<div id="ember-application-root">
</div>

JavaScript

// Ember Extensions by @ebryn
var get = Ember.get, set = Ember.set;

Ember.ListItemView = Ember.View.extend({
  classNames: ['list-item-view'],

  // Attribute bindings are too slow
  _updateStyle: function() {
    var e = get(this, 'element');
    if (e) { // WHY?
      e.style.top = get(this, 'top') + 'px';
    }
  },

  didInsertElement: function() {
    this._updateStyle();
  },

  serialize: function() {},
  prepareForReuse: function() {}
});

var get = Ember.get, set = Ember.set;

Ember.ListView = Ember.ContainerView.extend({
  classNames: ['list-view'],
  attributeBindings: ['style'],
  scrollTop: 0,
  itemViewClass: Ember.ListItemView,

  init: function() {
    this.contentDidChange(); // Setup array observing
    this._super();
  },

  style: Ember.computed(function() {
    return "height: " + get(this, 'height') + "px";
  }).property('height'),

  didInsertElement: function() {
    // FIXME: Don't need to render the list inside didInsertElement unless
    // we're going to support the ListView inheriting it's height from a
    // containing element.
    this._renderList();

    this.$().on('scroll', Ember.$.proxy(this.scroll, this));
  },

  willDestroyElement: function() {
    this.$().off('scroll', Ember.$.proxy(this.scroll, this));
  },

  // Browser fires the scroll event asynchronously
  scroll: function(e) {
    Ember.run(this, this.scrollTo, e.target.scrollTop);
  },

  _renderList: function() {
    this._createChildViews();
    this._appendScrollingView();
  },

  _rerenderList: function() {
    this.destroyAllChildren();
    this._renderList();
  },

  _createScrollingView: function() {
    return Ember.View.create({
      attributeBindings: ['style'],

      style: Ember.computed(function() {
        return "height: " + get(this, 'parentView.totalHeight') + "px";
      }).property('parentView.totalHeight')
    });
  },

  _appendScrollingView: function() {
    var childViews = get(this, 'childViews');
   ...