diff --git a/README.md b/README.md
index 45a6858..11deb15 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,28 @@ With a surrounding fixed height container with overflow scroll. Note that `overf
If you are running the plugin in the `skeleton-naviagion` project, make sure to remove `overflow-x: hidden;` and `overflow-y: auto;` from `.page-host` in `styles.css`.
+#### infinite scroll
+```html
+
+
+ ${$index} ${item}
+
+
+```
+
+```javascript
+export class MyVirtualList {
+ items = ['Foo', 'Bar', 'Baz'];
+ getMore() {
+ for(let i = 0; i < 100; ++i) {
+ this.items.push('item' + i);
+ }
+ }
+}
+```
+The `virtual-repeat-next` attribute can accept a function, a promise, or a function that returns a promise.
+The bound function will be called when the scroll container has reached a point where there are no more items to move into the DOM (i.e. when it reaches the end of a list).
+
## [Demo](http://aurelia.io/ui-virtualization/)
## Platform Support
diff --git a/build/tasks/test.js b/build/tasks/test.js
index c7af441..d26e93c 100644
--- a/build/tasks/test.js
+++ b/build/tasks/test.js
@@ -11,6 +11,16 @@ gulp.task('test', function (done) {
}, done).start();
});
+/**
+ * Run test and watch for changes
+ */
+gulp.task('test:watch', function (done) {
+ new Karma({
+ configFile: __dirname + '/../../karma.conf.js',
+ singleRun: false
+ }, done).start();
+});
+
/**
* Watch for file changes and re-run tests on each change
*/
diff --git a/config.js b/config.js
index b175fed..381ef54 100644
--- a/config.js
+++ b/config.js
@@ -14,10 +14,10 @@ System.config({
},
map: {
- "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.0",
- "aurelia-bootstrapper": "npm:aurelia-bootstrapper@1.0.0-beta.2.0.1",
+ "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.2",
+ "aurelia-bootstrapper": "npm:aurelia-bootstrapper@1.0.0-rc.1.0.1",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-rc.1.0.0",
- "aurelia-framework": "npm:aurelia-framework@1.0.0-rc.1.0.0",
+ "aurelia-framework": "npm:aurelia-framework@1.0.0-rc.1.0.1",
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
"aurelia-logging-console": "npm:aurelia-logging-console@1.0.0-rc.1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0-rc.1.0.0",
@@ -56,15 +56,15 @@ System.config({
"process": "github:jspm/nodelibs-process@0.1.2",
"util": "npm:util@0.10.3"
},
- "npm:aurelia-binding@1.0.0-rc.1.0.0": {
+ "npm:aurelia-binding@1.0.0-rc.1.0.2": {
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.0-rc.1.0.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0-rc.1.0.0",
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0-rc.1.0.0"
},
- "npm:aurelia-bootstrapper@1.0.0-beta.2.0.1": {
+ "npm:aurelia-bootstrapper@1.0.0-rc.1.0.1": {
"aurelia-event-aggregator": "npm:aurelia-event-aggregator@1.0.0-rc.1.0.0",
- "aurelia-framework": "npm:aurelia-framework@1.0.0-rc.1.0.0",
+ "aurelia-framework": "npm:aurelia-framework@1.0.0-rc.1.0.1",
"aurelia-history": "npm:aurelia-history@1.0.0-rc.1.0.0",
"aurelia-history-browser": "npm:aurelia-history-browser@1.0.0-rc.1.0.0",
"aurelia-loader-default": "npm:aurelia-loader-default@1.0.0-rc.1.0.0",
@@ -85,8 +85,8 @@ System.config({
"npm:aurelia-event-aggregator@1.0.0-rc.1.0.0": {
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0"
},
- "npm:aurelia-framework@1.0.0-rc.1.0.0": {
- "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.0",
+ "npm:aurelia-framework@1.0.0-rc.1.0.1": {
+ "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.2",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-rc.1.0.0",
"aurelia-loader": "npm:aurelia-loader@1.0.0-rc.1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
@@ -136,12 +136,12 @@ System.config({
"aurelia-pal": "npm:aurelia-pal@1.0.0-rc.1.0.0"
},
"npm:aurelia-templating-binding@1.0.0-rc.1.0.0": {
- "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.0",
+ "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.2",
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
"aurelia-templating": "npm:aurelia-templating@1.0.0-rc.1.0.0"
},
"npm:aurelia-templating-resources@1.0.0-rc.1.0.0": {
- "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.0",
+ "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.2",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-rc.1.0.0",
"aurelia-loader": "npm:aurelia-loader@1.0.0-rc.1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
@@ -161,7 +161,7 @@ System.config({
"aurelia-templating": "npm:aurelia-templating@1.0.0-rc.1.0.0"
},
"npm:aurelia-templating@1.0.0-rc.1.0.0": {
- "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.0",
+ "aurelia-binding": "npm:aurelia-binding@1.0.0-rc.1.0.2",
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0-rc.1.0.0",
"aurelia-loader": "npm:aurelia-loader@1.0.0-rc.1.0.0",
"aurelia-logging": "npm:aurelia-logging@1.0.0-rc.1.0.0",
diff --git a/dist/amd/aurelia-ui-virtualization.js b/dist/amd/aurelia-ui-virtualization.js
index fd730f6..5593c9a 100644
--- a/dist/amd/aurelia-ui-virtualization.js
+++ b/dist/amd/aurelia-ui-virtualization.js
@@ -1,14 +1,15 @@
-define(['exports', './virtual-repeat'], function (exports, _virtualRepeat) {
+define(['exports', './virtual-repeat', './virtual-repeat-next'], function (exports, _virtualRepeat, _virtualRepeatNext) {
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
- exports.VirtualRepeat = undefined;
+ exports.VirtualRepeatNext = exports.VirtualRepeat = undefined;
exports.configure = configure;
function configure(config) {
- config.globalResources('./virtual-repeat');
+ config.globalResources('./virtual-repeat', './virtual-repeat-next');
}
exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
+ exports.VirtualRepeatNext = _virtualRepeatNext.VirtualRepeatNext;
});
\ No newline at end of file
diff --git a/dist/amd/template-strategy.js b/dist/amd/template-strategy.js
index 162d844..abc0a17 100644
--- a/dist/amd/template-strategy.js
+++ b/dist/amd/template-strategy.js
@@ -46,11 +46,13 @@ define(['exports', 'aurelia-pal', 'aurelia-templating', './utilities'], function
};
TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
- (0, _utilities.insertBeforeNode)(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ (0, _utilities.insertBeforeNode)(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode));
};
TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- (0, _utilities.insertBeforeNode)(view, bottomBuffer.parentNode);
+ var previousSibling = bottomBuffer.parentNode.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ (0, _utilities.insertBeforeNode)(view, referenceNode);
};
TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
diff --git a/dist/amd/virtual-repeat-next.js b/dist/amd/virtual-repeat-next.js
new file mode 100644
index 0000000..ffc164e
--- /dev/null
+++ b/dist/amd/virtual-repeat-next.js
@@ -0,0 +1,26 @@
+define(['exports', 'aurelia-templating'], function (exports, _aureliaTemplating) {
+ 'use strict';
+
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.VirtualRepeatNext = undefined;
+
+
+
+ var _dec, _class;
+
+ var VirtualRepeatNext = exports.VirtualRepeatNext = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat-next'), _dec(_class = function () {
+ function VirtualRepeatNext() {
+
+ }
+
+ VirtualRepeatNext.prototype.attached = function attached() {};
+
+ VirtualRepeatNext.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ };
+
+ return VirtualRepeatNext;
+ }()) || _class);
+});
\ No newline at end of file
diff --git a/dist/amd/virtual-repeat.js b/dist/amd/virtual-repeat.js
index 599fd2a..be8ff60 100644
--- a/dist/amd/virtual-repeat.js
+++ b/dist/amd/virtual-repeat.js
@@ -6,6 +6,12 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
});
exports.VirtualRepeat = undefined;
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+ return typeof obj;
+ } : function (obj) {
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj;
+ };
+
function _initDefineProp(target, property, descriptor, context) {
if (!descriptor) return;
Object.defineProperty(target, property, {
@@ -103,6 +109,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
_this._fixedHeightContainer = false;
_this._hasCalculatedSizes = false;
_this._isAtTop = true;
+ _this._calledGetMore = false;
_initDefineProp(_this, 'items', _descriptor, _this);
@@ -276,6 +283,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -308,6 +316,45 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
this._ticking = false;
};
+ VirtualRepeat.prototype._getMore = function _getMore() {
+ var _this5 = this;
+
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ var _ret = function () {
+ var getMoreFunc = _this5.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return {
+ v: void 0
+ };
+ }
+ var getMore = _this5.scope.overrideContext.bindingContext[getMoreFunc];
+
+ _this5.observerLocator.taskQueue.queueMicroTask(function () {
+ _this5._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ var result = getMore.bind(_this5.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else {
+ _this5._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }();
+
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
+ }
+ }
+ };
+
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -346,7 +393,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
};
VirtualRepeat.prototype._moveViews = function _moveViews(length) {
- var _this5 = this;
+ var _this6 = this;
var getNextIndex = this._scrollingDown ? function (index, i) {
return index + i;
@@ -354,7 +401,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
+ return _this6._scrollingDown ? _this6.isLastIndex : _this6._isAtTop;
};
var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
diff --git a/dist/aurelia-ui-virtualization.d.ts b/dist/aurelia-ui-virtualization.d.ts
index 7c3d897..20cd987 100644
--- a/dist/aurelia-ui-virtualization.d.ts
+++ b/dist/aurelia-ui-virtualization.d.ts
@@ -1,3 +1,13 @@
+import {
+ customAttribute,
+ View,
+ BoundViewFactory,
+ ViewSlot,
+ ViewResources,
+ TargetInstruction,
+ bindable,
+ templateController
+} from 'aurelia-templating';
import {
updateOverrideContext,
ArrayRepeatStrategy,
@@ -10,16 +20,6 @@ import {
updateOneTimeBinding,
viewsRequireLifecycle
} from 'aurelia-templating-resources';
-import {
- View,
- BoundViewFactory,
- ViewSlot,
- ViewResources,
- TargetInstruction,
- customAttribute,
- bindable,
- templateController
-} from 'aurelia-templating';
import {
DOM
} from 'aurelia-pal';
@@ -43,6 +43,13 @@ export declare class DomHelper {
getElementDistanceToTopOfDocument(element: Element): number;
hasOverflowScroll(element: Element): boolean;
}
+
+//Placeholder attribute to prohibit use of this attribute name in other places
+export declare class VirtualRepeatNext {
+ constructor();
+ attached(): any;
+ bind(bindingContext?: any, overrideContext?: any): void;
+}
export declare function calcOuterHeight(element: Element): number;
export declare function insertBeforeNode(view: View, bottomBuffer: number): void;
diff --git a/dist/aurelia-ui-virtualization.js b/dist/aurelia-ui-virtualization.js
index 9610262..c591270 100644
--- a/dist/aurelia-ui-virtualization.js
+++ b/dist/aurelia-ui-virtualization.js
@@ -1,5 +1,5 @@
+import {customAttribute,View,BoundViewFactory,ViewSlot,ViewResources,TargetInstruction,bindable,templateController} from 'aurelia-templating';
import {updateOverrideContext,ArrayRepeatStrategy,createFullOverrideContext,RepeatStrategyLocator,AbstractRepeater,getItemsSourceExpression,isOneTime,unwrapExpression,updateOneTimeBinding,viewsRequireLifecycle} from 'aurelia-templating-resources';
-import {View,BoundViewFactory,ViewSlot,ViewResources,TargetInstruction,customAttribute,bindable,templateController} from 'aurelia-templating';
import {DOM} from 'aurelia-pal';
import {inject} from 'aurelia-dependency-injection';
import {ObserverLocator} from 'aurelia-binding';
@@ -20,6 +20,23 @@ export class DomHelper {
}
}
+//Placeholder attribute to prohibit use of this attribute name in other places
+
+@customAttribute('virtual-repeat-next')
+export class VirtualRepeatNext {
+
+ constructor(){
+ }
+
+ attached(){
+ }
+
+ bind(bindingContext, overrideContext): void {
+ this.scope = { bindingContext, overrideContext };
+ }
+
+}
+
export function calcOuterHeight(element: Element): number {
let height;
height = element.getBoundingClientRect().height;
@@ -393,11 +410,13 @@ export class TableStrategy {
}
moveViewFirst(view: View, topBuffer: Element): void {
- insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode));
}
moveViewLast(view: View, bottomBuffer: Element): void {
- insertBeforeNode(view, bottomBuffer.parentNode);
+ let previousSibling = bottomBuffer.parentNode.previousSibling;
+ let referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ insertBeforeNode(view, referenceNode);
}
createTopBufferElement(element: Element): Element {
@@ -507,6 +526,7 @@ export class VirtualRepeat extends AbstractRepeater {
_fixedHeightContainer = false;
_hasCalculatedSizes = false;
_isAtTop = true;
+ _calledGetMore = false;
@bindable items
@bindable local
@@ -686,6 +706,7 @@ export class VirtualRepeat extends AbstractRepeater {
this._lastRebind = this._first;
let movedViewsCount = this._moveViews(viewsToMove);
let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -718,6 +739,38 @@ export class VirtualRepeat extends AbstractRepeater {
this._ticking = false;
}
+ _getMore(): void{
+ if(this.isLastIndex){
+ if(!this._calledGetMore){
+ let getMoreFunc = this.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if(!getMoreFunc){
+ //break down the boogie
+ return;
+ }
+ let getMore = this.scope.overrideContext.bindingContext[getMoreFunc];
+
+ this.observerLocator.taskQueue.queueMicroTask(() =>{
+ this._calledGetMore = true;
+ if(getMore instanceof Promise){
+ return getMore.then(() => {
+ this._calledGetMore = false; //Reset for the next time
+ })
+ } else if (typeof getMore === 'function'){
+ let result = getMore.bind(this.scope.overrideContext.bindingContext)();
+ if(result instanceof Promise){
+ return result.then(() => {
+ this._calledGetMore = false; //Reset for the next time
+ })
+ } else {
+ this._calledGetMore = false; //Reset for the next time
+ return;
+ }
+ }
+ });
+ }
+ }
+ }
+
_checkScrolling(): void {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
diff --git a/dist/commonjs/aurelia-ui-virtualization.js b/dist/commonjs/aurelia-ui-virtualization.js
index fae8111..2613d33 100644
--- a/dist/commonjs/aurelia-ui-virtualization.js
+++ b/dist/commonjs/aurelia-ui-virtualization.js
@@ -3,13 +3,16 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
-exports.VirtualRepeat = undefined;
+exports.VirtualRepeatNext = exports.VirtualRepeat = undefined;
exports.configure = configure;
var _virtualRepeat = require('./virtual-repeat');
+var _virtualRepeatNext = require('./virtual-repeat-next');
+
function configure(config) {
- config.globalResources('./virtual-repeat');
+ config.globalResources('./virtual-repeat', './virtual-repeat-next');
}
-exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
\ No newline at end of file
+exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
+exports.VirtualRepeatNext = _virtualRepeatNext.VirtualRepeatNext;
\ No newline at end of file
diff --git a/dist/commonjs/template-strategy.js b/dist/commonjs/template-strategy.js
index 4df5160..b6c08d6 100644
--- a/dist/commonjs/template-strategy.js
+++ b/dist/commonjs/template-strategy.js
@@ -51,11 +51,13 @@ var TableStrategy = exports.TableStrategy = function () {
};
TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
- (0, _utilities.insertBeforeNode)(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ (0, _utilities.insertBeforeNode)(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode));
};
TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- (0, _utilities.insertBeforeNode)(view, bottomBuffer.parentNode);
+ var previousSibling = bottomBuffer.parentNode.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ (0, _utilities.insertBeforeNode)(view, referenceNode);
};
TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
diff --git a/dist/commonjs/virtual-repeat-next.js b/dist/commonjs/virtual-repeat-next.js
new file mode 100644
index 0000000..700dd2c
--- /dev/null
+++ b/dist/commonjs/virtual-repeat-next.js
@@ -0,0 +1,26 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtualRepeatNext = undefined;
+
+var _dec, _class;
+
+var _aureliaTemplating = require('aurelia-templating');
+
+
+
+var VirtualRepeatNext = exports.VirtualRepeatNext = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat-next'), _dec(_class = function () {
+ function VirtualRepeatNext() {
+
+ }
+
+ VirtualRepeatNext.prototype.attached = function attached() {};
+
+ VirtualRepeatNext.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ };
+
+ return VirtualRepeatNext;
+}()) || _class);
\ No newline at end of file
diff --git a/dist/commonjs/virtual-repeat.js b/dist/commonjs/virtual-repeat.js
index 5791dd1..0128344 100644
--- a/dist/commonjs/virtual-repeat.js
+++ b/dist/commonjs/virtual-repeat.js
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
});
exports.VirtualRepeat = undefined;
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
var _aureliaDependencyInjection = require('aurelia-dependency-injection');
@@ -100,6 +102,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
_this._fixedHeightContainer = false;
_this._hasCalculatedSizes = false;
_this._isAtTop = true;
+ _this._calledGetMore = false;
_initDefineProp(_this, 'items', _descriptor, _this);
@@ -273,6 +276,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -305,6 +309,45 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
this._ticking = false;
};
+ VirtualRepeat.prototype._getMore = function _getMore() {
+ var _this5 = this;
+
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ var _ret = function () {
+ var getMoreFunc = _this5.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return {
+ v: void 0
+ };
+ }
+ var getMore = _this5.scope.overrideContext.bindingContext[getMoreFunc];
+
+ _this5.observerLocator.taskQueue.queueMicroTask(function () {
+ _this5._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ var result = getMore.bind(_this5.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else {
+ _this5._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }();
+
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
+ }
+ }
+ };
+
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -343,7 +386,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
};
VirtualRepeat.prototype._moveViews = function _moveViews(length) {
- var _this5 = this;
+ var _this6 = this;
var getNextIndex = this._scrollingDown ? function (index, i) {
return index + i;
@@ -351,7 +394,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
+ return _this6._scrollingDown ? _this6.isLastIndex : _this6._isAtTop;
};
var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
diff --git a/dist/es2015/aurelia-ui-virtualization.js b/dist/es2015/aurelia-ui-virtualization.js
index 91b4a83..3ef0089 100644
--- a/dist/es2015/aurelia-ui-virtualization.js
+++ b/dist/es2015/aurelia-ui-virtualization.js
@@ -1,7 +1,8 @@
import { VirtualRepeat } from './virtual-repeat';
+import { VirtualRepeatNext } from './virtual-repeat-next';
export function configure(config) {
- config.globalResources('./virtual-repeat');
+ config.globalResources('./virtual-repeat', './virtual-repeat-next');
}
-export { VirtualRepeat };
\ No newline at end of file
+export { VirtualRepeat, VirtualRepeatNext };
\ No newline at end of file
diff --git a/dist/es2015/template-strategy.js b/dist/es2015/template-strategy.js
index 124aa00..705c23d 100644
--- a/dist/es2015/template-strategy.js
+++ b/dist/es2015/template-strategy.js
@@ -32,11 +32,13 @@ export let TableStrategy = class TableStrategy {
}
moveViewFirst(view, topBuffer) {
- insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode));
}
moveViewLast(view, bottomBuffer) {
- insertBeforeNode(view, bottomBuffer.parentNode);
+ let previousSibling = bottomBuffer.parentNode.previousSibling;
+ let referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ insertBeforeNode(view, referenceNode);
}
createTopBufferElement(element) {
diff --git a/dist/es2015/virtual-repeat-next.js b/dist/es2015/virtual-repeat-next.js
new file mode 100644
index 0000000..d946dc6
--- /dev/null
+++ b/dist/es2015/virtual-repeat-next.js
@@ -0,0 +1,15 @@
+var _dec, _class;
+
+import { customAttribute } from 'aurelia-templating';
+
+export let VirtualRepeatNext = (_dec = customAttribute('virtual-repeat-next'), _dec(_class = class VirtualRepeatNext {
+
+ constructor() {}
+
+ attached() {}
+
+ bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext, overrideContext };
+ }
+
+}) || _class);
\ No newline at end of file
diff --git a/dist/es2015/virtual-repeat.js b/dist/es2015/virtual-repeat.js
index c2bd0f7..3de1508 100644
--- a/dist/es2015/virtual-repeat.js
+++ b/dist/es2015/virtual-repeat.js
@@ -75,6 +75,7 @@ export let VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
this._fixedHeightContainer = false;
this._hasCalculatedSizes = false;
this._isAtTop = true;
+ this._calledGetMore = false;
_initDefineProp(this, 'items', _descriptor, this);
@@ -235,6 +236,7 @@ export let VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
this._lastRebind = this._first;
let movedViewsCount = this._moveViews(viewsToMove);
let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -267,6 +269,37 @@ export let VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
this._ticking = false;
}
+ _getMore() {
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ let getMoreFunc = this.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return;
+ }
+ let getMore = this.scope.overrideContext.bindingContext[getMoreFunc];
+
+ this.observerLocator.taskQueue.queueMicroTask(() => {
+ this._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(() => {
+ this._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ let result = getMore.bind(this.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(() => {
+ this._calledGetMore = false;
+ });
+ } else {
+ this._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }
+ }
+ }
+
_checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
diff --git a/dist/native-modules/aurelia-ui-virtualization.js b/dist/native-modules/aurelia-ui-virtualization.js
index 91b4a83..3ef0089 100644
--- a/dist/native-modules/aurelia-ui-virtualization.js
+++ b/dist/native-modules/aurelia-ui-virtualization.js
@@ -1,7 +1,8 @@
import { VirtualRepeat } from './virtual-repeat';
+import { VirtualRepeatNext } from './virtual-repeat-next';
export function configure(config) {
- config.globalResources('./virtual-repeat');
+ config.globalResources('./virtual-repeat', './virtual-repeat-next');
}
-export { VirtualRepeat };
\ No newline at end of file
+export { VirtualRepeat, VirtualRepeatNext };
\ No newline at end of file
diff --git a/dist/native-modules/template-strategy.js b/dist/native-modules/template-strategy.js
index bfab251..2b7e9a6 100644
--- a/dist/native-modules/template-strategy.js
+++ b/dist/native-modules/template-strategy.js
@@ -42,11 +42,13 @@ export var TableStrategy = function () {
};
TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
- insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode));
};
TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- insertBeforeNode(view, bottomBuffer.parentNode);
+ var previousSibling = bottomBuffer.parentNode.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ insertBeforeNode(view, referenceNode);
};
TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
diff --git a/dist/native-modules/virtual-repeat-next.js b/dist/native-modules/virtual-repeat-next.js
new file mode 100644
index 0000000..ef0cbc8
--- /dev/null
+++ b/dist/native-modules/virtual-repeat-next.js
@@ -0,0 +1,19 @@
+var _dec, _class;
+
+
+
+import { customAttribute } from 'aurelia-templating';
+
+export var VirtualRepeatNext = (_dec = customAttribute('virtual-repeat-next'), _dec(_class = function () {
+ function VirtualRepeatNext() {
+
+ }
+
+ VirtualRepeatNext.prototype.attached = function attached() {};
+
+ VirtualRepeatNext.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ };
+
+ return VirtualRepeatNext;
+}()) || _class);
\ No newline at end of file
diff --git a/dist/native-modules/virtual-repeat.js b/dist/native-modules/virtual-repeat.js
index eb1ab6b..3eb9013 100644
--- a/dist/native-modules/virtual-repeat.js
+++ b/dist/native-modules/virtual-repeat.js
@@ -1,3 +1,5 @@
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
function _initDefineProp(target, property, descriptor, context) {
@@ -85,6 +87,7 @@ export var VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
_this._fixedHeightContainer = false;
_this._hasCalculatedSizes = false;
_this._isAtTop = true;
+ _this._calledGetMore = false;
_initDefineProp(_this, 'items', _descriptor, _this);
@@ -258,6 +261,7 @@ export var VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -290,6 +294,45 @@ export var VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
this._ticking = false;
};
+ VirtualRepeat.prototype._getMore = function _getMore() {
+ var _this5 = this;
+
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ var _ret = function () {
+ var getMoreFunc = _this5.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return {
+ v: void 0
+ };
+ }
+ var getMore = _this5.scope.overrideContext.bindingContext[getMoreFunc];
+
+ _this5.observerLocator.taskQueue.queueMicroTask(function () {
+ _this5._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ var result = getMore.bind(_this5.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else {
+ _this5._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }();
+
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
+ }
+ }
+ };
+
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -328,7 +371,7 @@ export var VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
};
VirtualRepeat.prototype._moveViews = function _moveViews(length) {
- var _this5 = this;
+ var _this6 = this;
var getNextIndex = this._scrollingDown ? function (index, i) {
return index + i;
@@ -336,7 +379,7 @@ export var VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = in
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
+ return _this6._scrollingDown ? _this6.isLastIndex : _this6._isAtTop;
};
var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
diff --git a/dist/system/aurelia-ui-virtualization.js b/dist/system/aurelia-ui-virtualization.js
index 8825d7b..54bad09 100644
--- a/dist/system/aurelia-ui-virtualization.js
+++ b/dist/system/aurelia-ui-virtualization.js
@@ -1,21 +1,25 @@
'use strict';
-System.register(['./virtual-repeat'], function (_export, _context) {
+System.register(['./virtual-repeat', './virtual-repeat-next'], function (_export, _context) {
"use strict";
- var VirtualRepeat;
+ var VirtualRepeat, VirtualRepeatNext;
return {
setters: [function (_virtualRepeat) {
VirtualRepeat = _virtualRepeat.VirtualRepeat;
+ }, function (_virtualRepeatNext) {
+ VirtualRepeatNext = _virtualRepeatNext.VirtualRepeatNext;
}],
execute: function () {
function configure(config) {
- config.globalResources('./virtual-repeat');
+ config.globalResources('./virtual-repeat', './virtual-repeat-next');
}
_export('configure', configure);
_export('VirtualRepeat', VirtualRepeat);
+
+ _export('VirtualRepeatNext', VirtualRepeatNext);
}
};
});
\ No newline at end of file
diff --git a/dist/system/template-strategy.js b/dist/system/template-strategy.js
index 57e9a47..548a043 100644
--- a/dist/system/template-strategy.js
+++ b/dist/system/template-strategy.js
@@ -56,11 +56,13 @@ System.register(['aurelia-pal', 'aurelia-templating', './utilities'], function (
};
TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
- insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ insertBeforeNode(view, DOM.nextElementSibling(topBuffer.parentNode));
};
TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- insertBeforeNode(view, bottomBuffer.parentNode);
+ var previousSibling = bottomBuffer.parentNode.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ insertBeforeNode(view, referenceNode);
};
TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
diff --git a/dist/system/virtual-repeat-next.js b/dist/system/virtual-repeat-next.js
new file mode 100644
index 0000000..d0a6467
--- /dev/null
+++ b/dist/system/virtual-repeat-next.js
@@ -0,0 +1,32 @@
+'use strict';
+
+System.register(['aurelia-templating'], function (_export, _context) {
+ "use strict";
+
+ var customAttribute, _dec, _class, VirtualRepeatNext;
+
+
+
+ return {
+ setters: [function (_aureliaTemplating) {
+ customAttribute = _aureliaTemplating.customAttribute;
+ }],
+ execute: function () {
+ _export('VirtualRepeatNext', VirtualRepeatNext = (_dec = customAttribute('virtual-repeat-next'), _dec(_class = function () {
+ function VirtualRepeatNext() {
+
+ }
+
+ VirtualRepeatNext.prototype.attached = function attached() {};
+
+ VirtualRepeatNext.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ };
+
+ return VirtualRepeatNext;
+ }()) || _class));
+
+ _export('VirtualRepeatNext', VirtualRepeatNext);
+ }
+ };
+});
\ No newline at end of file
diff --git a/dist/system/virtual-repeat.js b/dist/system/virtual-repeat.js
index 47228f4..06e33cf 100644
--- a/dist/system/virtual-repeat.js
+++ b/dist/system/virtual-repeat.js
@@ -3,7 +3,7 @@
System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-templating', 'aurelia-templating-resources', 'aurelia-pal', './utilities', './dom-helper', './virtual-repeat-strategy-locator', './template-strategy'], function (_export, _context) {
"use strict";
- var inject, ObserverLocator, BoundViewFactory, ViewSlot, ViewResources, TargetInstruction, customAttribute, bindable, templateController, View, AbstractRepeater, getItemsSourceExpression, isOneTime, unwrapExpression, updateOneTimeBinding, viewsRequireLifecycle, DOM, getStyleValue, calcOuterHeight, rebindAndMoveView, DomHelper, VirtualRepeatStrategyLocator, TemplateStrategyLocator, _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2, VirtualRepeat;
+ var inject, ObserverLocator, BoundViewFactory, ViewSlot, ViewResources, TargetInstruction, customAttribute, bindable, templateController, View, AbstractRepeater, getItemsSourceExpression, isOneTime, unwrapExpression, updateOneTimeBinding, viewsRequireLifecycle, DOM, getStyleValue, calcOuterHeight, rebindAndMoveView, DomHelper, VirtualRepeatStrategyLocator, TemplateStrategyLocator, _typeof, _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2, VirtualRepeat;
function _initDefineProp(target, property, descriptor, context) {
if (!descriptor) return;
@@ -109,6 +109,12 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
TemplateStrategyLocator = _templateStrategy.TemplateStrategyLocator;
}],
execute: function () {
+ _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+ return typeof obj;
+ } : function (obj) {
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj;
+ };
+
_export('VirtualRepeat', VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = inject(DOM.Element, BoundViewFactory, TargetInstruction, ViewSlot, ViewResources, ObserverLocator, VirtualRepeatStrategyLocator, TemplateStrategyLocator, DomHelper), _dec(_class = templateController(_class = _dec2(_class = (_class2 = function (_AbstractRepeater) {
_inherits(VirtualRepeat, _AbstractRepeater);
@@ -135,6 +141,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
_this._fixedHeightContainer = false;
_this._hasCalculatedSizes = false;
_this._isAtTop = true;
+ _this._calledGetMore = false;
_initDefineProp(_this, 'items', _descriptor, _this);
@@ -308,6 +315,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -340,6 +348,45 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
this._ticking = false;
};
+ VirtualRepeat.prototype._getMore = function _getMore() {
+ var _this5 = this;
+
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ var _ret = function () {
+ var getMoreFunc = _this5.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return {
+ v: void 0
+ };
+ }
+ var getMore = _this5.scope.overrideContext.bindingContext[getMoreFunc];
+
+ _this5.observerLocator.taskQueue.queueMicroTask(function () {
+ _this5._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ var result = getMore.bind(_this5.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(function () {
+ _this5._calledGetMore = false;
+ });
+ } else {
+ _this5._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }();
+
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
+ }
+ }
+ };
+
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -378,7 +425,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
};
VirtualRepeat.prototype._moveViews = function _moveViews(length) {
- var _this5 = this;
+ var _this6 = this;
var getNextIndex = this._scrollingDown ? function (index, i) {
return index + i;
@@ -386,7 +433,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
+ return _this6._scrollingDown ? _this6.isLastIndex : _this6._isAtTop;
};
var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
diff --git a/dist/temp/aurelia-ui-virtualization.js b/dist/temp/aurelia-ui-virtualization.js
index 6129588..ea2c48d 100644
--- a/dist/temp/aurelia-ui-virtualization.js
+++ b/dist/temp/aurelia-ui-virtualization.js
@@ -3,9 +3,11 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
-exports.VirtualRepeat = exports.VirtualRepeatStrategyLocator = exports.DefaultTemplateStrategy = exports.TableStrategy = exports.TemplateStrategyLocator = exports.ArrayVirtualRepeatStrategy = exports.DomHelper = undefined;
+exports.VirtualRepeat = exports.VirtualRepeatStrategyLocator = exports.DefaultTemplateStrategy = exports.TableStrategy = exports.TemplateStrategyLocator = exports.ArrayVirtualRepeatStrategy = exports.VirtualRepeatNext = exports.DomHelper = undefined;
-var _dec, _dec2, _class2, _desc, _value, _class3, _descriptor, _descriptor2;
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
+var _dec, _class, _dec2, _dec3, _class3, _desc, _value, _class4, _descriptor, _descriptor2;
exports.calcOuterHeight = calcOuterHeight;
exports.insertBeforeNode = insertBeforeNode;
@@ -15,10 +17,10 @@ exports.getStyleValue = getStyleValue;
exports.getElementDistanceToBottomViewPort = getElementDistanceToBottomViewPort;
exports.getElementDistanceToTopViewPort = getElementDistanceToTopViewPort;
-var _aureliaTemplatingResources = require('aurelia-templating-resources');
-
var _aureliaTemplating = require('aurelia-templating');
+var _aureliaTemplatingResources = require('aurelia-templating-resources');
+
var _aureliaPal = require('aurelia-pal');
var _aureliaDependencyInjection = require('aurelia-dependency-injection');
@@ -96,6 +98,19 @@ var DomHelper = exports.DomHelper = function () {
return DomHelper;
}();
+var VirtualRepeatNext = exports.VirtualRepeatNext = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat-next'), _dec(_class = function () {
+ function VirtualRepeatNext() {
+ _classCallCheck(this, VirtualRepeatNext);
+ }
+
+ VirtualRepeatNext.prototype.attached = function attached() {};
+
+ VirtualRepeatNext.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ };
+
+ return VirtualRepeatNext;
+}()) || _class);
function calcOuterHeight(element) {
var height = void 0;
height = element.getBoundingClientRect().height;
@@ -465,11 +480,13 @@ var TableStrategy = exports.TableStrategy = function () {
};
TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
- insertBeforeNode(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode).previousSibling);
+ insertBeforeNode(view, _aureliaPal.DOM.nextElementSibling(topBuffer.parentNode));
};
TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- insertBeforeNode(view, bottomBuffer.parentNode);
+ var previousSibling = bottomBuffer.parentNode.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer.parentNode;
+ insertBeforeNode(view, referenceNode);
};
TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
@@ -578,7 +595,7 @@ var VirtualRepeatStrategyLocator = exports.VirtualRepeatStrategyLocator = functi
return VirtualRepeatStrategyLocator;
}(_aureliaTemplatingResources.RepeatStrategyLocator);
-var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec2 = (0, _aureliaDependencyInjection.inject)(_aureliaPal.DOM.Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaTemplating.ViewResources, _aureliaBinding.ObserverLocator, VirtualRepeatStrategyLocator, TemplateStrategyLocator, DomHelper), _dec(_class2 = (0, _aureliaTemplating.templateController)(_class2 = _dec2(_class2 = (_class3 = function (_AbstractRepeater) {
+var VirtualRepeat = exports.VirtualRepeat = (_dec2 = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec3 = (0, _aureliaDependencyInjection.inject)(_aureliaPal.DOM.Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaTemplating.ViewResources, _aureliaBinding.ObserverLocator, VirtualRepeatStrategyLocator, TemplateStrategyLocator, DomHelper), _dec2(_class3 = (0, _aureliaTemplating.templateController)(_class3 = _dec3(_class3 = (_class4 = function (_AbstractRepeater) {
_inherits(VirtualRepeat, _AbstractRepeater);
function VirtualRepeat(element, viewFactory, instruction, viewSlot, viewResources, observerLocator, strategyLocator, templateStrategyLocator, domHelper) {
@@ -604,6 +621,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
_this5._fixedHeightContainer = false;
_this5._hasCalculatedSizes = false;
_this5._isAtTop = true;
+ _this5._calledGetMore = false;
_initDefineProp(_this5, 'items', _descriptor, _this5);
@@ -777,6 +795,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -809,6 +828,45 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
this._ticking = false;
};
+ VirtualRepeat.prototype._getMore = function _getMore() {
+ var _this9 = this;
+
+ if (this.isLastIndex) {
+ if (!this._calledGetMore) {
+ var _ret2 = function () {
+ var getMoreFunc = _this9.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if (!getMoreFunc) {
+ return {
+ v: void 0
+ };
+ }
+ var getMore = _this9.scope.overrideContext.bindingContext[getMoreFunc];
+
+ _this9.observerLocator.taskQueue.queueMicroTask(function () {
+ _this9._calledGetMore = true;
+ if (getMore instanceof Promise) {
+ return getMore.then(function () {
+ _this9._calledGetMore = false;
+ });
+ } else if (typeof getMore === 'function') {
+ var result = getMore.bind(_this9.scope.overrideContext.bindingContext)();
+ if (result instanceof Promise) {
+ return result.then(function () {
+ _this9._calledGetMore = false;
+ });
+ } else {
+ _this9._calledGetMore = false;
+ return;
+ }
+ }
+ });
+ }();
+
+ if ((typeof _ret2 === 'undefined' ? 'undefined' : _typeof(_ret2)) === "object") return _ret2.v;
+ }
+ }
+ };
+
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -847,7 +905,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
};
VirtualRepeat.prototype._moveViews = function _moveViews(length) {
- var _this9 = this;
+ var _this10 = this;
var getNextIndex = this._scrollingDown ? function (index, i) {
return index + i;
@@ -855,7 +913,7 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this9._scrollingDown ? _this9.isLastIndex : _this9._isAtTop;
+ return _this10._scrollingDown ? _this10.isLastIndex : _this10._isAtTop;
};
var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
@@ -1014,10 +1072,10 @@ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.custo
};
return VirtualRepeat;
-}(_aureliaTemplatingResources.AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class3.prototype, 'items', [_aureliaTemplating.bindable], {
+}(_aureliaTemplatingResources.AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class4.prototype, 'items', [_aureliaTemplating.bindable], {
enumerable: true,
initializer: null
-}), _descriptor2 = _applyDecoratedDescriptor(_class3.prototype, 'local', [_aureliaTemplating.bindable], {
+}), _descriptor2 = _applyDecoratedDescriptor(_class4.prototype, 'local', [_aureliaTemplating.bindable], {
enumerable: true,
initializer: null
-})), _class3)) || _class2) || _class2) || _class2);
\ No newline at end of file
+})), _class4)) || _class3) || _class3) || _class3);
\ No newline at end of file
diff --git a/package.json b/package.json
index eda0ff6..f9f4b3a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "aurelia-ui-virtualization",
- "version": "1.0.0-beta.1.0.0",
+ "version": "1.0.0-beta.1.0.1",
"description": "A plugin that provides a virtualized repeater and other virtualization services.",
"keywords": [
"aurelia",
@@ -21,7 +21,6 @@
},
"jspm": {
"registry": "npm",
- "jspmPackage": true,
"main": "aurelia-ui-virtualization",
"format": "amd",
"directories": {
diff --git a/src/aurelia-ui-virtualization.js b/src/aurelia-ui-virtualization.js
index f63630b..83af475 100644
--- a/src/aurelia-ui-virtualization.js
+++ b/src/aurelia-ui-virtualization.js
@@ -1,11 +1,14 @@
import {VirtualRepeat} from './virtual-repeat';
+import {VirtualRepeatNext} from './virtual-repeat-next';
export function configure(config) {
config.globalResources(
- './virtual-repeat'
+ './virtual-repeat',
+ './virtual-repeat-next'
);
}
export {
- VirtualRepeat
+ VirtualRepeat,
+ VirtualRepeatNext
};
diff --git a/src/virtual-repeat-next.js b/src/virtual-repeat-next.js
new file mode 100644
index 0000000..3e3577a
--- /dev/null
+++ b/src/virtual-repeat-next.js
@@ -0,0 +1,18 @@
+import {customAttribute} from 'aurelia-templating';
+
+//Placeholder attribute to prohibit use of this attribute name in other places
+
+@customAttribute('virtual-repeat-next')
+export class VirtualRepeatNext {
+
+ constructor(){
+ }
+
+ attached(){
+ }
+
+ bind(bindingContext, overrideContext): void {
+ this.scope = { bindingContext, overrideContext };
+ }
+
+}
diff --git a/src/virtual-repeat.js b/src/virtual-repeat.js
index 20ca9c3..8e9dcdb 100644
--- a/src/virtual-repeat.js
+++ b/src/virtual-repeat.js
@@ -47,6 +47,7 @@ export class VirtualRepeat extends AbstractRepeater {
_fixedHeightContainer = false;
_hasCalculatedSizes = false;
_isAtTop = true;
+ _calledGetMore = false;
@bindable items
@bindable local
@@ -226,6 +227,7 @@ export class VirtualRepeat extends AbstractRepeater {
this._lastRebind = this._first;
let movedViewsCount = this._moveViews(viewsToMove);
let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._getMore();
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
@@ -258,6 +260,38 @@ export class VirtualRepeat extends AbstractRepeater {
this._ticking = false;
}
+ _getMore(): void{
+ if(this.isLastIndex){
+ if(!this._calledGetMore){
+ let getMoreFunc = this.view(0).firstChild.getAttribute('virtual-repeat-next');
+ if(!getMoreFunc){
+ //break down the boogie
+ return;
+ }
+ let getMore = this.scope.overrideContext.bindingContext[getMoreFunc];
+
+ this.observerLocator.taskQueue.queueMicroTask(() =>{
+ this._calledGetMore = true;
+ if(getMore instanceof Promise){
+ return getMore.then(() => {
+ this._calledGetMore = false; //Reset for the next time
+ })
+ } else if (typeof getMore === 'function'){
+ let result = getMore.bind(this.scope.overrideContext.bindingContext)();
+ if(result instanceof Promise){
+ return result.then(() => {
+ this._calledGetMore = false; //Reset for the next time
+ })
+ } else {
+ this._calledGetMore = false; //Reset for the next time
+ return;
+ }
+ }
+ });
+ }
+ }
+ }
+
_checkScrolling(): void {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
diff --git a/test/virtual-repeat-integration.spec.js b/test/virtual-repeat-integration.spec.js
index 9f55f52..c4ee573 100644
--- a/test/virtual-repeat-integration.spec.js
+++ b/test/virtual-repeat-integration.spec.js
@@ -63,6 +63,50 @@ describe('VirtualRepeat Integration', () => {
}
}
+ function validateScrolledState() {
+ let views = virtualRepeat.viewSlot.children;
+ let expectedHeight = viewModel.items.length * itemHeight;
+ let topBufferHeight = virtualRepeat.topBuffer.getBoundingClientRect().height;
+ let bottomBufferHeight = virtualRepeat.bottomBuffer.getBoundingClientRect().height;
+ let renderedItemsHeight = views.length * itemHeight;
+ expect(topBufferHeight + renderedItemsHeight + bottomBufferHeight).toBe(expectedHeight);
+
+ if(viewModel.items.length > views.length) {
+ expect(topBufferHeight + bottomBufferHeight).toBeGreaterThan(0);
+ }
+
+ // validate contextual data
+ let startingLoc = viewModel.items.indexOf(views[0].bindingContext.item);
+ for (let i = startingLoc; i < views.length; i++) {
+ expect(views[i].bindingContext.item).toBe(viewModel.items[i]);
+ let overrideContext = views[i].overrideContext;
+ expect(overrideContext.parentOverrideContext.bindingContext).toBe(viewModel);
+ expect(overrideContext.bindingContext).toBe(views[i].bindingContext);
+ let first = i === 0;
+ let last = i === viewModel.items.length - 1;
+ let even = i % 2 === 0;
+ expect(overrideContext.$index).toBe(i);
+ expect(overrideContext.$first).toBe(first);
+ expect(overrideContext.$last).toBe(last);
+ expect(overrideContext.$middle).toBe(!first && !last);
+ expect(overrideContext.$odd).toBe(!even);
+ expect(overrideContext.$even).toBe(even);
+ }
+ }
+
+ function validateScroll(done) {
+ let elem = document.getElementById('scrollContainer');
+ let event = new Event('scroll');
+ elem.scrollTop = elem.scrollHeight;
+ elem.dispatchEvent(event);
+ window.setTimeout(()=>{
+ window.requestAnimationFrame(() => {
+ validateScrolledState();
+ done();
+ });
+ });
+ }
+
function validatePush(done) {
viewModel.items.push('Foo');
nq(() => validateState());
@@ -309,4 +353,60 @@ describe('VirtualRepeat Integration', () => {
create.then(() => validateSplice(done));
});
});
+
+ describe('infinite scroll', () =>{
+ let vm;
+ beforeEach(() => {
+ items = [];
+ vm = {
+ items: items,
+ getNextPage: function(){
+ let itemLength = this.items.length;
+ for(let i = 0; i < 100; ++i) {
+ let itemNum = itemLength + i;
+ this.items.push('item' + itemNum);
+ }
+ }
+ };
+ for(let i = 0; i < 1000; ++i) {
+ items.push('item' + i);
+ }
+
+ spyOn(vm, 'getNextPage').and.callThrough();
+
+ component = StageComponent
+ .withResources(['src/virtual-repeat', 'src/virtual-repeat-next'])
+ .inView(`
`)
+ .boundTo(vm);
+
+ create = component.create().then(() => {
+ virtualRepeat = component.sut;
+ viewModel = component.viewModel;
+ spyOn(virtualRepeat, '_onScroll').and.callThrough();
+ });
+ });
+
+ afterEach(() => {
+ component.cleanUp();
+ });
+
+ it('handles scrolling', done => {
+ create.then(() => {
+ validateScroll(() => {
+ expect(virtualRepeat._onScroll).toHaveBeenCalled();
+ done();
+ })
+ });
+ })
+ it('handles getting next data set', done => {
+ create.then(() => {
+ validateScroll(() => {
+ expect(vm.getNextPage).toHaveBeenCalled();
+ done();
+ })
+ });
+ })
+ })
});