diff --git a/js/angular/directive/collectionRepeat.js b/js/angular/directive/collectionRepeat.js index d905e8e845..7326d0de22 100644 --- a/js/angular/directive/collectionRepeat.js +++ b/js/angular/directive/collectionRepeat.js @@ -13,7 +13,7 @@ function($collectionRepeatManager, $collectionRepeatDataSource, $parse) { link: function($scope, $element, $attr, scrollCtrl, $transclude) { var scrollView = scrollCtrl.scrollView; if (scrollView.options.scrollingX && scrollView.options.scrollingY) { - throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose only one."); + throw new Error("Cannot create a collection-repeat within a scrollView that is scrollable on both x and y axis. Choose either x direction or y direction."); } var isVertical = !!scrollView.options.scrollingY; @@ -57,13 +57,14 @@ function($collectionRepeatManager, $collectionRepeatDataSource, $parse) { dataSource.setData(value); collectionRepeatManager.resize(); }); - ionic.on('resize', function() { - collectionRepeatManager.resize(); - }, window); + + var resize = angular.bind(collectionRepeatManager, collectionRepeatManager.resize); + ionic.on('resize', resize, window); $scope.$on('$destroy', function() { collectionRepeatManager.destroy(); dataSource.destroy(); + ionic.off('resize', resize, window); }); } }; diff --git a/js/angular/service/collectionRepeatDataSource.js b/js/angular/service/collectionRepeatDataSource.js index 4d548af6d9..a22b0876db 100644 --- a/js/angular/service/collectionRepeatDataSource.js +++ b/js/angular/service/collectionRepeatDataSource.js @@ -67,15 +67,10 @@ function($cacheFactory, $parse) { this.dimensions = this.data.map(function(value, index) { locals[this.keyExpr] = value; locals.$index = index; - var ret = { + return { width: this.widthGetter(this.scope, locals), - height: this.heightGetter(this.scope, locals), - totalWidth: totalWidth, - totalHeight: totalHeight + height: this.heightGetter(this.scope, locals) }; - totalWidth += ret.width; - totalHeight += ret.height; - return ret; }, this); this.totalWidth = totalWidth; this.totalHeight = totalHeight; @@ -91,7 +86,7 @@ function($cacheFactory, $parse) { this.transcludeFn(item.scope, function(clone) { item.element = clone; - item.element[0].classList.add('scroll-collection-item'); + item.element[0].style.position = 'absolute'; }); return this.itemCache.put(key, item); @@ -101,7 +96,7 @@ function($cacheFactory, $parse) { var item = this.compileItem(index, value); if (item.scope.$index !== index) { - item.scope.$index = item.index = index; + item.scope.$index = index; item.scope.$first = (index === 0); item.scope.$last = (index === (this.getLength() - 1)); item.scope.$middle = !(item.scope.$first || item.scope.$last); @@ -131,7 +126,7 @@ function($cacheFactory, $parse) { return this.data && this.data.length || 0; }, setData: function(value) { - this.data = value; + this.data = value || []; this.calculateDataDimensions(); }, }; diff --git a/js/angular/service/collectionRepeatManager.js b/js/angular/service/collectionRepeatManager.js index 48bc879c66..03b0e1e723 100644 --- a/js/angular/service/collectionRepeatManager.js +++ b/js/angular/service/collectionRepeatManager.js @@ -4,7 +4,6 @@ IonicModule '$rootScope', '$timeout', function($rootScope, $timeout) { - var BUFFER_SPACES = 1; function CollectionRepeatManager(options) { var self = this; this.dataSource = options.dataSource; @@ -13,10 +12,6 @@ function($rootScope, $timeout) { this.itemSizePrimary = options.itemSizePrimary; this.itemSizeSecondary = options.itemSizeSecondary; - if (this.scrollView.options.scrollingX && this.scrollView.options.scrollingY) { - throw new Error("TODO MOVE THIS ERROR TO THE DIRECTIVE. Cannot create a scrollCollectionRepeatManager on an element that scrolls both x and y. Choose one, yo!"); - } - this.isVertical = !!this.scrollView.options.scrollingY; this.renderedItems = {}; @@ -26,32 +21,20 @@ function($rootScope, $timeout) { this.scrollView.__$callback = this.scrollView.__callback; this.scrollView.__callback = angular.bind(this, this.renderScroll); - function getter(prop) { - return self[prop]; - } - - function getItemHeight(item) { return item.height; } - function getItemWidth(item) { return item.width; } - function getItemTotalHeight(item) { return item.totalHeight; } - function getItemTotalWidth(item) { return item.totalWidth; } function getViewportSize() { return self.viewportSize; } if (this.isVertical) { this.scrollView.options.getContentHeight = getViewportSize; - this.itemSizePrimary = getItemHeight; - this.itemSizeSecondary = getItemWidth; - this.itemTotalSizePrimary = getItemTotalHeight; - this.itemTotalSizeSecondary = getItemTotalWidth; - this.getScrollValue = function() { + this.scrollValue = function() { return this.scrollView.__scrollTop; }; - this.getScrollMaxValue = function() { + this.scrollMaxValue = function() { return this.scrollView.__maxScrollTop; }; - this.getScrollSize = function() { + this.scrollSize = function() { return this.scrollView.__clientHeight; }; - this.getScrollSizeSecondary = function() { + this.getSecondaryScrollSize = function() { return this.scrollView.__clientWidth; }; this.transformString = function(y, x) { @@ -59,19 +42,17 @@ function($rootScope, $timeout) { }; } else { this.scrollView.options.getContentWidth = getViewportSize; - this.itemSizePrimary = getItemWidth; - this.itemSizeSecondary = getItemHeight; - this.itemTotalSizePrimary = getItemTotalWidth; - this.itemTotalSizeSecondary = getItemTotalHeight; - this.getScrollValue = function() { return this.scrollView.__scrollLeft; }; - this.getScrollMaxValue = function() { + this.scrollValue = function() { + return this.scrollView.__scrollLeft; + }; + this.scrollMaxValue = function() { return this.scrollView.__maxScrollLeft; }; - this.getScrollSize = function() { + this.scrollSize = function() { return this.scrollView.__clientWidth; }; - this.getScrollSizeSecondary = function() { + this.getSecondaryScrollSize = function() { return this.scrollView.__clientHeight; }; this.transformString = function(x, y) { @@ -87,26 +68,51 @@ function($rootScope, $timeout) { } }, resize: function() { - this.viewportSize = this.isVertical ? - this.dataSource.totalHeight : - this.dataSource.totalWidth; this.scrollView.resize(); + + var primaryPos = 0; + var secondaryPos = 0; + var itemsPerSpace = 0; + var len = this.dataSource.dimensions.length; + this.dimensions = this.dataSource.dimensions.map(function(dimensions, index) { + var rect = { + primarySize: this.isVertical ? dimensions.height : dimensions.width, + secondarySize: this.isVertical ? dimensions.width: dimensions.height, + primaryPos: primaryPos, + secondaryPos: secondaryPos + }; + + if (secondaryPos + rect.secondarySize >= this.getSecondaryScrollSize()) { + secondaryPos = 0; + primaryPos += rect.primarySize; + + rect.primaryPos = primaryPos; + rect.secondaryPos = secondaryPos; + if (!this.itemsPerSpace) { + this.itemsPerSpace = itemsPerSpace; + } + } + itemsPerSpace++; + secondaryPos += rect.secondarySize; + + return rect; + }, this); + + this.viewportSize = primaryPos; this.setCurrentIndex(0); this.lastRenderScrollValue = 0; this.render(true); }, setCurrentIndex: function(index, height) { - var dimensions = this.dataSource.dimensions; this.currentIndex = index; this.hasPrevIndex = index > 0; if (this.hasPrevIndex) { - this.prevTotalHeight = dimensions[index - 1].totalHeight; + this.previousPos = this.dimensions[index - 1].primaryPos; } this.hasNextIndex = index + 1 < this.dataSource.getLength(); if (this.hasNextIndex) { - this.nextTotalHeight = dimensions[index + 1].totalHeight; - this.nextHeight = dimensions[index + 1].height; + this.nextPos = this.dimensions[index + 1].primaryPos; } }, renderScroll: ionic.animationFrameThrottle(function(transformLeft, transformTop, zoom, wasResize) { @@ -118,25 +124,24 @@ function($rootScope, $timeout) { return this.scrollView.__$callback(transformLeft, transformTop, zoom, wasResize); }), getTransformPosition: function(transformPos) { - if ((this.hasNextIndex && transformPos >= this.nextTotalHeight) || - (this.hasPrevIndex && transformPos < this.prevTotalHeight) || + if ((this.hasNextIndex && transformPos >= this.nextPos) || + (this.hasPrevIndex && transformPos < this.previousPos) || Math.abs(transformPos - this.lastRenderScrollValue) > 100) { this.render(); } return transformPos - this.lastRenderScrollValue; }, getIndexForScrollValue: function(i, scrollValue) { - var dimensions = this.dataSource.dimensions; var rect; - //Scrolling up - if (scrollValue <= dimensions[i].totalHeight) { - while ( (rect = dimensions[i - 1]) && rect.totalHeight > scrollValue) { - i--; - } //Scrolling down + if (scrollValue <= this.dimensions[i].primaryPos) { + while ( (rect = this.dimensions[i - 1]) && rect.primaryPos > scrollValue) { + i -= this.itemsPerSpace; + } + //Scrolling up } else { - while ( (rect = dimensions[i + 1]) && rect.totalHeight < scrollValue) { - i++; + while ( (rect = this.dimensions[i + 1]) && rect.primaryPos < scrollValue) { + i += this.itemsPerSpace; } } return i; @@ -148,28 +153,22 @@ function($rootScope, $timeout) { this.removeItem(i); } } - var scrollValue = this.getScrollValue(); + var scrollValue = this.scrollValue(); var scrollDelta = scrollValue - this.lastRenderScrollValue; - var scrollSize = this.getScrollSize(); + var scrollSize = this.scrollSize(); var scrollSizeEnd = scrollSize + scrollValue; - var dimensions = this.dataSource.dimensions; - var startIndex = this.getIndexForScrollValue(this.currentIndex, scrollValue); - var bufferStartIndex = Math.max(0, startIndex - 1); - var startHeight = dimensions[bufferStartIndex].totalHeight; + var bufferStartIndex = Math.max(0, startIndex - this.itemsPerSpace); + var startPos = this.dimensions[bufferStartIndex].primaryPos; i = bufferStartIndex; var rect; - while ( (rect = dimensions[i]) && (rect.totalHeight - rect.height) < scrollSizeEnd) { - this.renderItem(i, rect.totalHeight - startHeight, 0); + while ((rect = this.dimensions[i]) && (rect.primaryPos - rect.primarySize < scrollSizeEnd)) { + this.renderItem(i, rect.primaryPos - startPos, rect.secondaryPos); i++; } - var endIndex = i - 1; - var bufferEndIndex = Math.min(this.dataSource.getLength() - 1, endIndex + 1); - if (bufferEndIndex !== endIndex) { - this.renderItem(bufferEndIndex, dimensions[bufferEndIndex].totalHeight - startHeight, 0); - } + var bufferEndIndex = i -1; for (i in this.renderedItems) { if (i < bufferStartIndex || i > bufferEndIndex) { @@ -178,7 +177,7 @@ function($rootScope, $timeout) { } this.setCurrentIndex(startIndex); - this.lastRenderScrollValue = startHeight; + this.lastRenderScrollValue = startPos; if (!this.dataSource.scope.$$phase) { this.dataSource.scope.$digest(); @@ -200,6 +199,7 @@ function($rootScope, $timeout) { removeItem: function(dataIndex) { var item = this.renderedItems[dataIndex]; if (item) { + console.log('removing', dataIndex, item); this.dataSource.detachItem(item); delete this.renderedItems[dataIndex]; } diff --git a/scss/_util.scss b/scss/_util.scss index 9153769413..f772a0b174 100644 --- a/scss/_util.scss +++ b/scss/_util.scss @@ -4,9 +4,6 @@ * -------------------------------------------------- */ -.scroll-collection-item { - position: absolute !important; -} .hide { display: none; } diff --git a/test/html/list-fit.html b/test/html/list-fit.html index 30e406f061..c0e2d2758a 100644 --- a/test/html/list-fit.html +++ b/test/html/list-fit.html @@ -23,7 +23,9 @@
+ collection-item-height="52" + collection-item-width="120 + 2*($index % 40)" + ng-style="{width: 120 + 2*($index % 40)}"> {{item}}
@@ -62,10 +64,5 @@ function MainCtrl($scope, $ionicScrollDelegate, $timeout) { $scope.scrollBottom = $ionicScrollDelegate.scrollBottom; } -