mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
collection-repeat: enable grid functionality
This commit is contained in:
9
js/angular/directive/collectionRepeat.js
vendored
9
js/angular/directive/collectionRepeat.js
vendored
@@ -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);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
15
js/angular/service/collectionRepeatDataSource.js
vendored
15
js/angular/service/collectionRepeatDataSource.js
vendored
@@ -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();
|
||||
},
|
||||
};
|
||||
|
||||
120
js/angular/service/collectionRepeatManager.js
vendored
120
js/angular/service/collectionRepeatManager.js
vendored
@@ -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];
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
* --------------------------------------------------
|
||||
*/
|
||||
|
||||
.scroll-collection-item {
|
||||
position: absolute !important;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user