collection-repeat: enable grid functionality

This commit is contained in:
Andy Joslin
2014-04-24 05:15:22 -06:00
parent 5722900a58
commit e5e5b911f7
5 changed files with 73 additions and 83 deletions

View File

@@ -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);
});
}
};

View File

@@ -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();
},
};

View File

@@ -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];
}

View File

@@ -4,9 +4,6 @@
* --------------------------------------------------
*/
.scroll-collection-item {
position: absolute !important;
}
.hide {
display: none;
}

View File

@@ -23,7 +23,9 @@
<div class="item"
ng-click="alert(item)"
collection-repeat="item in items"
collection-item-height="52 + 3*($index % 52)">
collection-item-height="52"
collection-item-width="120 + 2*($index % 40)"
ng-style="{width: 120 + 2*($index % 40)}">
{{item}}
</div>
</div>
@@ -62,10 +64,5 @@ function MainCtrl($scope, $ionicScrollDelegate, $timeout) {
$scope.scrollBottom = $ionicScrollDelegate.scrollBottom;
}
</script>
<style>
.item {
left: 0;
right: 0;
}
</body>
</html>