Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Various Fixes #28

Open
wants to merge 4 commits into from

1 participant

@grippy

I noticed an issue where ListView.prototype.append would take longer and longer if you were working with really long pages.

After digging into it:

  • There's seems to be an issue with how jquery computes .outerHeight(true) and .height(). The longer the page, the longer these take to compute. I'm using the useElementScroll value on something so I don't have an infinite page (rather a display: auto container with a fixed height).

This pull request makes it possible to do this now:

Assuming we have a list of DOM elements:

      for (var i = 0, len = $els.length, item; i < len; i++) {
        item = $($els[i]);
        if (i === 0) {
          item = infinity.convertToItem(this.listView, item);
          cache = item;
        } else {
          item = new infinity.ListItem(item);
          // pre-cache the height/width
          // so we don't spend anytime trying to compute them
          item.height = cache.height;
          item.width = cache.width;
          infinity.cacheCoordsFor(this.listView, item);
        }
        this.listView.append(item);
      }

In addition, I also added a few small enhancements to not compute the parent.height() every time hasVacancy is called.

It doesn't appear the build files were generated after merging the 2 previous pull requests.

I left some comments in there. I can take these out if you prefer.

grippy added some commits
@grippy grippy use local coffee script bin 86ef83e
@grippy grippy 1. ListView.prototype.append never accounted for a ListItem being pas…
…sed through

2. Exposes infinity.convertToItem and infinity.cacheCoordsFor to make ListItem instantion outside of ListView.prototype.append
3. ListItem now skips setting height and width if it already has that value
4. Pages.prototype.hasVacancy now caches parent height if using element scrolling
cb93148
@grippy grippy don't test for array using Array.isArray since this isn't support by IE8 02668c7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 19, 2013
  1. @grippy

    use local coffee script bin

    grippy authored
  2. @grippy

    1. ListView.prototype.append never accounted for a ListItem being pas…

    grippy authored
    …sed through
    
    2. Exposes infinity.convertToItem and infinity.cacheCoordsFor to make ListItem instantion outside of ListView.prototype.append
    3. ListItem now skips setting height and width if it already has that value
    4. Pages.prototype.hasVacancy now caches parent height if using element scrolling
  3. @grippy
  4. @grippy
This page is out of date. Refresh to see the latest.
Showing with 138 additions and 32 deletions.
  1. +1 −1  Makefile
  2. +78 −18 build/infinity.js
  3. +2 −2 build/infinity.min.js
  4. +57 −11 infinity.js
View
2  Makefile
@@ -11,7 +11,7 @@ annotate:
@./node_modules/.bin/docco infinity.js
build-test:
- @coffee -c test/
+ @./node_modules/.bin/coffee -c test/
build: clean build-js build-test
View
96 build/infinity.js
@@ -1,5 +1,6 @@
+
// (c) 2012 Airbnb, Inc.
-//
+//
// infinity.js may be freely distributed under the terms of the BSD
// license. For all licensing information, details, and documention:
// http://airbnb.github.com/infinity
@@ -79,6 +80,17 @@
this.lazy = !!options.lazy;
this.lazyFn = options.lazy || null;
+ this.loadFn = options.load || null;
+
+ this.useElementScroll = options.useElementScroll === true;
+
+ // [grippy] Use this to pass an option to set
+ // the width and height for all ListItem's
+ // cacheItemDimensions = {width: int, height: int}
+ // if either width or height is missing
+ // the width or height will default to the
+ // first page item width or height
+ this.cacheItemDimensions = options.cacheItemDimensions;
initBuffer(this);
@@ -89,6 +101,8 @@
this.pages = [];
this.startIndex = 0;
+ this.$scrollParent = this.useElementScroll ? $el : $window;
+
DOMEvent.attach(this);
}
@@ -136,14 +150,19 @@
// TODO: optimized batch appends
ListView.prototype.append = function(obj) {
- if(!obj || !obj.length) return null;
+
+ // [grippy] A ListItem won't be an array
+ // so check if we have an empty array
+ if(!obj || (obj instanceof Array) && !obj.length) return null;
var lastPage,
item = convertToItem(this, obj),
pages = this.pages;
this.height += item.height;
- this.$el.height(this.height);
+
+ // [grippy] css lookup should be faster here
+ this.$el.css('height', this.height);
lastPage = pages[pages.length - 1];
@@ -152,9 +171,19 @@
pages.push(lastPage);
}
+ // [grippy] should we cache the dimensions for this item?
+ // cacheItemDimensions allows for passing an object
+ // with width and height
+ // if we don't have a width and height
+ // use the item.width and/or item.height
+ // as computed by jquery
+ if (this.cacheItemDimensions && !lastPage.itemHeight) {
+ lastPage.itemWidth = this.cacheItemDimensions.width || Number(item.width);
+ lastPage.itemHeight = this.cacheItemDimensions.height || Number(item.height);
+ }
+
lastPage.append(item);
insertPagesInView(this);
-
return item;
};
@@ -169,13 +198,23 @@
// - `listItem`: the ListItem whose coordinates you want to cache.
function cacheCoordsFor(listView, listItem) {
- listItem.$el.remove();
+ listItem.$el.detach();
// WARNING: this will always break for prepends. Once support gets added for
// prepends, change this.
listView.$el.append(listItem.$el);
+
+ // [grippy] should we cache the dimensions for this item?
+ var pages = listView.pages;
+ var lastPage = pages[pages.length - 1];
+ if (listView.cacheItemDimensions &&
+ lastPage &&
+ lastPage.itemHeight) {
+ listItem.width = lastPage.itemWidth;
+ listItem.height = lastPage.itemHeight;
+ }
updateCoords(listItem, listView.height);
- listItem.$el.remove();
+ listItem.$el.detach();
}
@@ -226,8 +265,9 @@
function updateStartIndex(listView) {
var index, length, pages, lastIndex, nextLastIndex,
startIndex = listView.startIndex,
- viewTop = $window.scrollTop() - listView.top,
- viewHeight = $window.height(),
+ viewRef = listView.$scrollParent,
+ viewTop = viewRef.scrollTop() - listView.top,
+ viewHeight = viewRef.height(),
viewBottom = viewTop + viewHeight,
nextIndex = startIndexWithinRange(listView, viewTop, viewBottom);
@@ -246,6 +286,8 @@
listView.startIndex = nextIndex;
+ if(listView.loadFn) listView.loadFn.call(listView, pages.length - nextLastIndex);
+
insertPagesInView(listView);
updateBuffer(listView);
return nextIndex;
@@ -558,8 +600,12 @@
// event.
attach: function(listView) {
+ if(!listView.eventIsBound) {
+ listView.$scrollParent.on('scroll', scrollHandler);
+ listView.eventIsBound = true;
+ }
+
if(!eventIsBound) {
- $window.on('scroll', scrollHandler);
$window.on('resize', resizeHandler);
eventIsBound = true;
}
@@ -582,11 +628,15 @@
detach: function(listView) {
var index, length;
+ if(listView.eventIsBound) {
+ listView.$scrollParent.on('scroll', scrollHandler);
+ listView.eventIsBound = false;
+ }
+
for(index = 0, length = boundViews.length; index < length; index++) {
if(boundViews[index] === listView) {
boundViews.splice(index, 1);
if(boundViews.length === 0) {
- $window.off('scroll', scrollHandler);
$window.off('resize', resizeHandler);
eventIsBound = false;
}
@@ -680,7 +730,18 @@
// Returns false if the Page is at max capacity; false otherwise.
Page.prototype.hasVacancy = function() {
- return this.height < $window.height() * config.PAGE_TO_SCREEN_RATIO;
+ var viewRef = this.parent.$scrollParent;
+ var parentHeight;
+ // [grippy] while using element scroll
+ // cache the parent height
+ // since it shouldn't change
+ if (this.parent.useElementScroll) {
+ if (!this.parentHeight) this.parentHeight = viewRef.height();
+ parentHeight = this.parentHeight;
+ } else {
+ parentHeight = viewRef.height();
+ }
+ return this.height < parentHeight * config.PAGE_TO_SCREEN_RATIO;
};
@@ -725,7 +786,7 @@
Page.prototype.remove = function() {
if(this.onscreen) {
- this.$el.remove();
+ this.$el.detach();
this.onscreen = false;
}
this.cleanup();
@@ -829,9 +890,7 @@
function ListItem($el) {
this.$el = $el;
-
this.parent = null;
-
this.top = 0;
this.bottom = 0;
this.width = 0;
@@ -884,11 +943,10 @@
function updateCoords(listItem, yOffset) {
var $el = listItem.$el;
-
listItem.top = yOffset;
- listItem.height = $el.outerHeight(true);
+ if (!listItem.height) listItem.height = $el.outerHeight(true);
listItem.bottom = listItem.top + listItem.height;
- listItem.width = $el.width();
+ if (!listItem.width) listItem.width = $el.width();
}
@@ -932,6 +990,8 @@
infinity.ListView = ListView;
infinity.Page = Page;
infinity.ListItem = ListItem;
+ infinity.convertToItem = convertToItem;
+ infinity.cacheCoordsFor = cacheCoordsFor;
//jQuery plugin
function registerPlugin(infinity) {
@@ -957,4 +1017,4 @@
return infinity;
};
-}(window, Math, jQuery);
+}(window, Math, jQuery);
View
4 build/infinity.min.js
@@ -1,6 +1,6 @@
// (c) 2012 Airbnb, Inc.
-//
+//
// infinity.js may be freely distributed under the terms of the BSD
// license. For all licensing information, details, and documention:
// http://airbnb.github.com/infinity
-!function(e,t,n){"use strict";function l(e,t){t=t||{},this.$el=k(),this.$shadow=k(),e.append(this.$el),this.lazy=!!t.lazy,this.lazyFn=t.lazy||null,c(this),this.top=this.$el.offset().top,this.width=0,this.height=0,this.pages=[],this.startIndex=0,E.attach(this)}function c(e){e._$buffer=k().prependTo(e.$el)}function h(e){var t,n=e.pages,r=e._$buffer;n.length>0?(t=n[e.startIndex],r.height(t.top)):r.height(0)}function p(e,t){t.$el.remove(),e.$el.append(t.$el),C(t,e.height),t.$el.remove()}function d(e){var n,r,i,s=e.pages,o=!1,u=!0;n=e.startIndex,r=t.min(n+f,s.length);for(n;n<r;n++)i=s[n],e.lazy&&i.lazyload(e.lazyFn),o&&i.onscreen&&(u=!1),u?i.onscreen||(o=!0,i.appendTo(e.$el)):(i.stash(e.$shadow),i.appendTo(e.$el))}function v(e){var n,i,s,o,u,a=e.startIndex,l=r.scrollTop()-e.top,c=r.height(),p=l+c,v=b(e,l,p);if(v<0||v===a)return a;s=e.pages,a=e.startIndex,o=t.min(a+f,s.length),u=t.min(v+f,s.length);for(n=a,i=o;n<i;n++)(n<v||n>=u)&&s[n].stash(e.$shadow);return e.startIndex=v,d(e),h(e),v}function m(e,t){var r;return t instanceof N?t:(typeof t=="string"&&(t=n(t)),r=new N(t),p(e,r),r)}function g(e,t){y(e)}function y(e){var t,n,r,i,s,o,u,a,f,l=e.pages,c=[];n=new S(e),c.push(n);for(r=0,i=l.length;r<i;r++){t=l[r],u=t.items;for(s=0,o=u.length;s<o;s++)a=u[s],f=a.clone(),n.hasVacancy()?n.append(f):(n=new S(e),c.push(n),n.append(f));t.remove()}e.pages=c,d(e)}function b(e,n,r){var i=w(e,n,r);return i=t.max(i-a,0),i=t.min(i,e.pages.length),i}function w(e,n,r){var i,s,o,u,f,l,c,h=e.pages,p=n+(r-n)/2;u=t.min(e.startIndex+a,h.length-1);if(h.length<=0)return-1;o=h[u],f=o.top+o.height/2,c=p-f;if(c<0){for(i=u-1;i>=0;i--){o=h[i],f=o.top+o.height/2,l=p-f;if(l>0)return l<-c?i:i+1;c=l}return 0}if(c>0){for(i=u+1,s=h.length;i<s;i++){o=h[i],f=o.top+o.height/2,l=p-f;if(l<0)return-l<c?i:i-1;c=l}return h.length-1}return u}function S(e){this.parent=e,this.items=[],this.$el=k(),this.id=x.generatePageId(this),this.$el.attr(u,this.id),this.top=0,this.bottom=0,this.width=0,this.height=0,this.lazyloaded=!1,this.onscreen=!1}function T(e,t){var n,r,i,s=t.items;for(n=0,r=s.length;n<r;n++)if(s[n]===e){i=n;break}return i==null?!1:(s.splice(i,1),t.bottom-=e.height,t.height=t.bottom-t.top,t.hasVacancy()&&g(t.parent,t),!0)}function N(e){this.$el=e,this.parent=null,this.top=0,this.bottom=0,this.width=0,this.height=0}function C(e,t){var n=e.$el;e.top=t,e.height=n.outerHeight(!0),e.bottom=e.top+e.height,e.width=n.width()}function k(){return n("<div>").css({margin:0,padding:0,border:"none"})}function L(e){var t;e?(t=e.ListView,n.fn.listView=function(e){return new t(this,e)}):delete n.fn.listView}var r=n(e),i=e.infinity,s=e.infinity={},o=s.config={},u="data-infinity-pageid",a=1,f=a*2+1;o.PAGE_TO_SCREEN_RATIO=3,o.SCROLL_THROTTLE=350,l.prototype.append=function(e){if(!e||!e.length)return null;var t,n=m(this,e),r=this.pages;this.height+=n.height,this.$el.height(this.height),t=r[r.length-1];if(!t||!t.hasVacancy())t=new S(this),r.push(t);return t.append(n),d(this),n},l.prototype.remove=function(){this.$el.remove(),this.cleanup()},l.prototype.find=function(e){var t,r,i;return typeof e=="string"?(r=this.$el.find(e),i=this.$shadow.find(e),this.find(r).concat(this.find(i))):e instanceof N?[e]:(t=[],e.each(function(){var e,r,i,s,o,a,f=n(this).parentsUntil("["+u+"]").andSelf().first(),l=f.parent();e=l.attr(u),r=x.lookup(e);if(r){i=r.items;for(s=0,o=i.length;s<o;s++){a=i[s];if(a.$el.is(f)){t.push(a);break}}}}),t)},l.prototype.cleanup=function(){var e=this.pages,t;E.detach(this);while(t=e.pop())t.cleanup()};var E=function(){function s(){t||(setTimeout(u,o.SCROLL_THROTTLE),t=!0)}function u(){var e,n;for(e=0,n=i.length;e<n;e++)v(i[e]);t=!1}function a(){n&&clearTimeout(n),n=setTimeout(f,200)}function f(){var e,t;for(e=0;t=i[e];e++)y(t)}var e=!1,t=!1,n=null,i=[];return{attach:function(t){e||(r.on("scroll",s),r.on("resize",a),e=!0),i.push(t)},detach:function(t){var n,o;for(n=0,o=i.length;n<o;n++)if(i[n]===t)return i.splice(n,1),i.length===0&&(r.off("scroll",s),r.off("resize",a),e=!1),!0;return!1}}}();S.prototype.append=function(e){var t=this.items;t.length===0&&(this.top=e.top),this.bottom=e.bottom,this.width=this.width>e.width?this.width:e.width,this.height=this.bottom-this.top,t.push(e),e.parent=this,this.$el.append(e.$el),this.lazyloaded=!1},S.prototype.prepend=function(e){var t=this.items;this.bottom+=e.height,this.width=this.width>e.width?this.width:e.width,this.height=this.bottom-this.top,t.push(e),e.parent=this,this.$el.prepend(e.$el),this.lazyloaded=!1},S.prototype.hasVacancy=function(){return this.height<r.height()*o.PAGE_TO_SCREEN_RATIO},S.prototype.appendTo=function(e){this.onscreen||(this.$el.appendTo(e),this.onscreen=!0)},S.prototype.prependTo=function(e){this.onscreen||(this.$el.prependTo(e),this.onscreen=!0)},S.prototype.stash=function(e){this.onscreen&&(this.$el.appendTo(e),this.onscreen=!1)},S.prototype.remove=function(){this.onscreen&&(this.$el.remove(),this.onscreen=!1),this.cleanup()},S.prototype.cleanup=function(){var e=this.items,t;this.parent=null,x.remove(this);while(t=e.pop())t.cleanup()},S.prototype.lazyload=function(e){var t=this.$el,n,r;if(!this.lazyloaded){for(n=0,r=t.length;n<r;n++)e.call(t[n],t[n]);this.lazyloaded=!0}};var x=function(){var e=[];return{generatePageId:function(t){return e.push(t)-1},lookup:function(t){return e[t]||null},remove:function(t){var n=t.id;return e[n]?(e[n]=null,!0):!1}}}();N.prototype.clone=function(){var e=new N(this.$el);return e.top=this.top,e.bottom=this.bottom,e.width=this.width,e.height=this.height,e},N.prototype.remove=function(){this.$el.remove(),T(this,this.parent),this.cleanup()},N.prototype.cleanup=function(){this.parent=null},s.ListView=l,s.Page=S,s.ListItem=N,L(s),s.noConflict=function(){return e.infinity=i,L(i),s}}(window,Math,jQuery);
+!function(e,t,n){"use strict";function l(e,t){t=t||{},this.$el=k(),this.$shadow=k(),e.append(this.$el),this.lazy=!!t.lazy,this.lazyFn=t.lazy||null,this.loadFn=t.load||null,this.useElementScroll=t.useElementScroll===!0,this.cacheItemDimensions=t.cacheItemDimensions,c(this),this.top=this.$el.offset().top,this.width=0,this.height=0,this.pages=[],this.startIndex=0,this.$scrollParent=this.useElementScroll?e:r,E.attach(this)}function c(e){e._$buffer=k().prependTo(e.$el)}function h(e){var t,n=e.pages,r=e._$buffer;n.length>0?(t=n[e.startIndex],r.height(t.top)):r.height(0)}function p(e,t){t.$el.detach(),e.$el.append(t.$el);var n=e.pages,r=n[n.length-1];e.cacheItemDimensions&&r&&r.itemHeight&&(t.width=r.itemWidth,t.height=r.itemHeight),C(t,e.height),t.$el.detach()}function d(e){var n,r,i,s=e.pages,o=!1,u=!0;n=e.startIndex,r=t.min(n+f,s.length);for(n;n<r;n++)i=s[n],e.lazy&&i.lazyload(e.lazyFn),o&&i.onscreen&&(u=!1),u?i.onscreen||(o=!0,i.appendTo(e.$el)):(i.stash(e.$shadow),i.appendTo(e.$el))}function v(e){var n,r,i,s,o,u=e.startIndex,a=e.$scrollParent,l=a.scrollTop()-e.top,c=a.height(),p=l+c,v=b(e,l,p);if(v<0||v===u)return u;i=e.pages,u=e.startIndex,s=t.min(u+f,i.length),o=t.min(v+f,i.length);for(n=u,r=s;n<r;n++)(n<v||n>=o)&&i[n].stash(e.$shadow);return e.startIndex=v,e.loadFn&&e.loadFn.call(e,i.length-o),d(e),h(e),v}function m(e,t){var r;return t instanceof N?t:(typeof t=="string"&&(t=n(t)),r=new N(t),p(e,r),r)}function g(e,t){y(e)}function y(e){var t,n,r,i,s,o,u,a,f,l=e.pages,c=[];n=new S(e),c.push(n);for(r=0,i=l.length;r<i;r++){t=l[r],u=t.items;for(s=0,o=u.length;s<o;s++)a=u[s],f=a.clone(),n.hasVacancy()?n.append(f):(n=new S(e),c.push(n),n.append(f));t.remove()}e.pages=c,d(e)}function b(e,n,r){var i=w(e,n,r);return i=t.max(i-a,0),i=t.min(i,e.pages.length),i}function w(e,n,r){var i,s,o,u,f,l,c,h=e.pages,p=n+(r-n)/2;u=t.min(e.startIndex+a,h.length-1);if(h.length<=0)return-1;o=h[u],f=o.top+o.height/2,c=p-f;if(c<0){for(i=u-1;i>=0;i--){o=h[i],f=o.top+o.height/2,l=p-f;if(l>0)return l<-c?i:i+1;c=l}return 0}if(c>0){for(i=u+1,s=h.length;i<s;i++){o=h[i],f=o.top+o.height/2,l=p-f;if(l<0)return-l<c?i:i-1;c=l}return h.length-1}return u}function S(e){this.parent=e,this.items=[],this.$el=k(),this.id=x.generatePageId(this),this.$el.attr(u,this.id),this.top=0,this.bottom=0,this.width=0,this.height=0,this.lazyloaded=!1,this.onscreen=!1}function T(e,t){var n,r,i,s=t.items;for(n=0,r=s.length;n<r;n++)if(s[n]===e){i=n;break}return i==null?!1:(s.splice(i,1),t.bottom-=e.height,t.height=t.bottom-t.top,t.hasVacancy()&&g(t.parent,t),!0)}function N(e){this.$el=e,this.parent=null,this.top=0,this.bottom=0,this.width=0,this.height=0}function C(e,t){var n=e.$el;e.top=t,e.height||(e.height=n.outerHeight(!0)),e.bottom=e.top+e.height,e.width||(e.width=n.width())}function k(){return n("<div>").css({margin:0,padding:0,border:"none"})}function L(e){var t;e?(t=e.ListView,n.fn.listView=function(e){return new t(this,e)}):delete n.fn.listView}var r=n(e),i=e.infinity,s=e.infinity={},o=s.config={},u="data-infinity-pageid",a=1,f=a*2+1;o.PAGE_TO_SCREEN_RATIO=3,o.SCROLL_THROTTLE=350,l.prototype.append=function(e){if(!e||e instanceof Array&&!e.length)return null;var t,n=m(this,e),r=this.pages;this.height+=n.height,this.$el.css("height",this.height),t=r[r.length-1];if(!t||!t.hasVacancy())t=new S(this),r.push(t);return this.cacheItemDimensions&&!t.itemHeight&&(t.itemWidth=this.cacheItemDimensions.width||Number(n.width),t.itemHeight=this.cacheItemDimensions.height||Number(n.height)),t.append(n),d(this),n},l.prototype.remove=function(){this.$el.remove(),this.cleanup()},l.prototype.find=function(e){var t,r,i;return typeof e=="string"?(r=this.$el.find(e),i=this.$shadow.find(e),this.find(r).concat(this.find(i))):e instanceof N?[e]:(t=[],e.each(function(){var e,r,i,s,o,a,f=n(this).parentsUntil("["+u+"]").andSelf().first(),l=f.parent();e=l.attr(u),r=x.lookup(e);if(r){i=r.items;for(s=0,o=i.length;s<o;s++){a=i[s];if(a.$el.is(f)){t.push(a);break}}}}),t)},l.prototype.cleanup=function(){var e=this.pages,t;E.detach(this);while(t=e.pop())t.cleanup()};var E=function(){function s(){t||(setTimeout(u,o.SCROLL_THROTTLE),t=!0)}function u(){var e,n;for(e=0,n=i.length;e<n;e++)v(i[e]);t=!1}function a(){n&&clearTimeout(n),n=setTimeout(f,200)}function f(){var e,t;for(e=0;t=i[e];e++)y(t)}var e=!1,t=!1,n=null,i=[];return{attach:function(t){t.eventIsBound||(t.$scrollParent.on("scroll",s),t.eventIsBound=!0),e||(r.on("resize",a),e=!0),i.push(t)},detach:function(t){var n,o;t.eventIsBound&&(t.$scrollParent.on("scroll",s),t.eventIsBound=!1);for(n=0,o=i.length;n<o;n++)if(i[n]===t)return i.splice(n,1),i.length===0&&(r.off("resize",a),e=!1),!0;return!1}}}();S.prototype.append=function(e){var t=this.items;t.length===0&&(this.top=e.top),this.bottom=e.bottom,this.width=this.width>e.width?this.width:e.width,this.height=this.bottom-this.top,t.push(e),e.parent=this,this.$el.append(e.$el),this.lazyloaded=!1},S.prototype.prepend=function(e){var t=this.items;this.bottom+=e.height,this.width=this.width>e.width?this.width:e.width,this.height=this.bottom-this.top,t.push(e),e.parent=this,this.$el.prepend(e.$el),this.lazyloaded=!1},S.prototype.hasVacancy=function(){var e=this.parent.$scrollParent,t;return this.parent.useElementScroll?(this.parentHeight||(this.parentHeight=e.height()),t=this.parentHeight):t=e.height(),this.height<t*o.PAGE_TO_SCREEN_RATIO},S.prototype.appendTo=function(e){this.onscreen||(this.$el.appendTo(e),this.onscreen=!0)},S.prototype.prependTo=function(e){this.onscreen||(this.$el.prependTo(e),this.onscreen=!0)},S.prototype.stash=function(e){this.onscreen&&(this.$el.appendTo(e),this.onscreen=!1)},S.prototype.remove=function(){this.onscreen&&(this.$el.detach(),this.onscreen=!1),this.cleanup()},S.prototype.cleanup=function(){var e=this.items,t;this.parent=null,x.remove(this);while(t=e.pop())t.cleanup()},S.prototype.lazyload=function(e){var t=this.$el,n,r;if(!this.lazyloaded){for(n=0,r=t.length;n<r;n++)e.call(t[n],t[n]);this.lazyloaded=!0}};var x=function(){var e=[];return{generatePageId:function(t){return e.push(t)-1},lookup:function(t){return e[t]||null},remove:function(t){var n=t.id;return e[n]?(e[n]=null,!0):!1}}}();N.prototype.clone=function(){var e=new N(this.$el);return e.top=this.top,e.bottom=this.bottom,e.width=this.width,e.height=this.height,e},N.prototype.remove=function(){this.$el.remove(),T(this,this.parent),this.cleanup()},N.prototype.cleanup=function(){this.parent=null},s.ListView=l,s.Page=S,s.ListItem=N,s.convertToItem=m,s.cacheCoordsFor=p,L(s),s.noConflict=function(){return e.infinity=i,L(i),s}}(window,Math,jQuery);
View
68 infinity.js
@@ -1,5 +1,6 @@
+
// (c) 2012 Airbnb, Inc.
-//
+//
// infinity.js may be freely distributed under the terms of the BSD
// license. For all licensing information, details, and documention:
// http://airbnb.github.com/infinity
@@ -79,9 +80,18 @@
this.lazy = !!options.lazy;
this.lazyFn = options.lazy || null;
+ this.loadFn = options.load || null;
this.useElementScroll = options.useElementScroll === true;
+ // [grippy] Use this to pass an option to set
+ // the width and height for all ListItem's
+ // cacheItemDimensions = {width: int, height: int}
+ // if either width or height is missing
+ // the width or height will default to the
+ // first page item width or height
+ this.cacheItemDimensions = options.cacheItemDimensions;
+
initBuffer(this);
this.top = this.$el.offset().top;
@@ -140,14 +150,19 @@
// TODO: optimized batch appends
ListView.prototype.append = function(obj) {
- if(!obj || !obj.length) return null;
+
+ // [grippy] A ListItem won't be an array
+ // so check if we have an empty array
+ if(!obj || (obj instanceof Array) && !obj.length) return null;
var lastPage,
item = convertToItem(this, obj),
pages = this.pages;
this.height += item.height;
- this.$el.height(this.height);
+
+ // [grippy] css lookup should be faster here
+ this.$el.css('height', this.height);
lastPage = pages[pages.length - 1];
@@ -156,9 +171,19 @@
pages.push(lastPage);
}
+ // [grippy] should we cache the dimensions for this item?
+ // cacheItemDimensions allows for passing an object
+ // with width and height
+ // if we don't have a width and height
+ // use the item.width and/or item.height
+ // as computed by jquery
+ if (this.cacheItemDimensions && !lastPage.itemHeight) {
+ lastPage.itemWidth = this.cacheItemDimensions.width || Number(item.width);
+ lastPage.itemHeight = this.cacheItemDimensions.height || Number(item.height);
+ }
+
lastPage.append(item);
insertPagesInView(this);
-
return item;
};
@@ -178,6 +203,16 @@
// WARNING: this will always break for prepends. Once support gets added for
// prepends, change this.
listView.$el.append(listItem.$el);
+
+ // [grippy] should we cache the dimensions for this item?
+ var pages = listView.pages;
+ var lastPage = pages[pages.length - 1];
+ if (listView.cacheItemDimensions &&
+ lastPage &&
+ lastPage.itemHeight) {
+ listItem.width = lastPage.itemWidth;
+ listItem.height = lastPage.itemHeight;
+ }
updateCoords(listItem, listView.height);
listItem.$el.detach();
}
@@ -251,6 +286,8 @@
listView.startIndex = nextIndex;
+ if(listView.loadFn) listView.loadFn.call(listView, pages.length - nextLastIndex);
+
insertPagesInView(listView);
updateBuffer(listView);
return nextIndex;
@@ -694,7 +731,17 @@
Page.prototype.hasVacancy = function() {
var viewRef = this.parent.$scrollParent;
- return this.height < viewRef.height() * config.PAGE_TO_SCREEN_RATIO;
+ var parentHeight;
+ // [grippy] while using element scroll
+ // cache the parent height
+ // since it shouldn't change
+ if (this.parent.useElementScroll) {
+ if (!this.parentHeight) this.parentHeight = viewRef.height();
+ parentHeight = this.parentHeight;
+ } else {
+ parentHeight = viewRef.height();
+ }
+ return this.height < parentHeight * config.PAGE_TO_SCREEN_RATIO;
};
@@ -843,9 +890,7 @@
function ListItem($el) {
this.$el = $el;
-
this.parent = null;
-
this.top = 0;
this.bottom = 0;
this.width = 0;
@@ -898,11 +943,10 @@
function updateCoords(listItem, yOffset) {
var $el = listItem.$el;
-
listItem.top = yOffset;
- listItem.height = $el.outerHeight(true);
+ if (!listItem.height) listItem.height = $el.outerHeight(true);
listItem.bottom = listItem.top + listItem.height;
- listItem.width = $el.width();
+ if (!listItem.width) listItem.width = $el.width();
}
@@ -946,6 +990,8 @@
infinity.ListView = ListView;
infinity.Page = Page;
infinity.ListItem = ListItem;
+ infinity.convertToItem = convertToItem;
+ infinity.cacheCoordsFor = cacheCoordsFor;
//jQuery plugin
function registerPlugin(infinity) {
@@ -971,4 +1017,4 @@
return infinity;
};
-}(window, Math, jQuery);
+}(window, Math, jQuery);
Something went wrong with that request. Please try again.