Skip to content

Commit

Permalink
collection-repeat: enable grid functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
ajoslin committed Apr 24, 2014
1 parent 5722900 commit e5e5b91
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 83 deletions.
9 changes: 5 additions & 4 deletions js/angular/directive/collectionRepeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
});
}
};
Expand Down
15 changes: 5 additions & 10 deletions js/angular/service/collectionRepeatDataSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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();
},
};
Expand Down
120 changes: 60 additions & 60 deletions js/angular/service/collectionRepeatManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ IonicModule
'$rootScope',
'$timeout',
function($rootScope, $timeout) {
var BUFFER_SPACES = 1;
function CollectionRepeatManager(options) {
var self = this;
this.dataSource = options.dataSource;
Expand All @@ -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 = {};

Expand All @@ -26,52 +21,38 @@ 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) {
return 'translate3d('+x+'px,'+y+'px,0)';
};
} 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) {
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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();
Expand All @@ -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];
}
Expand Down
3 changes: 0 additions & 3 deletions scss/_util.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
* --------------------------------------------------
*/

.scroll-collection-item {
position: absolute !important;
}
.hide {
display: none;
}
Expand Down
9 changes: 3 additions & 6 deletions test/html/list-fit.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ <h1 class="title">Hi</h1>
<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>
Expand Down Expand Up @@ -62,10 +64,5 @@ <h1 class="title">Hi</h1>
$scope.scrollBottom = $ionicScrollDelegate.scrollBottom;
}
</script>
<style>
.item {
left: 0;
right: 0;
}
</body>
</html>

0 comments on commit e5e5b91

Please sign in to comment.