diff --git a/bower.json b/bower.json
index 80274b8..f5e9c15 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "aurelia-ui-virtualization",
- "version": "0.3.2",
+ "version": "0.4.0",
"description": "A plugin that provides a virtualized repeater and other virtualization services.",
"keywords": [
"aurelia",
diff --git a/dist/amd/array-virtual-repeat-strategy.js b/dist/amd/array-virtual-repeat-strategy.js
index d2062e9..df37790 100644
--- a/dist/amd/array-virtual-repeat-strategy.js
+++ b/dist/amd/array-virtual-repeat-strategy.js
@@ -1,26 +1,53 @@
-define(['exports', 'aurelia-templating-resources/array-repeat-strategy', 'aurelia-templating-resources/repeat-utilities'], function (exports, _aureliaTemplatingResourcesArrayRepeatStrategy, _aureliaTemplatingResourcesRepeatUtilities) {
+define(['exports', 'aurelia-templating-resources/array-repeat-strategy', 'aurelia-templating-resources/repeat-utilities', './utilities'], function (exports, _arrayRepeatStrategy, _repeatUtilities, _utilities) {
'use strict';
- exports.__esModule = true;
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.ArrayVirtualRepeatStrategy = undefined;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
- function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
- var ArrayVirtualRepeatStrategy = (function (_ArrayRepeatStrategy) {
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
+ var ArrayVirtualRepeatStrategy = exports.ArrayVirtualRepeatStrategy = function (_ArrayRepeatStrategy) {
_inherits(ArrayVirtualRepeatStrategy, _ArrayRepeatStrategy);
function ArrayVirtualRepeatStrategy() {
_classCallCheck(this, ArrayVirtualRepeatStrategy);
- _ArrayRepeatStrategy.apply(this, arguments);
+ return _possibleConstructorReturn(this, _ArrayRepeatStrategy.apply(this, arguments));
}
ArrayVirtualRepeatStrategy.prototype.createFirstItem = function createFirstItem(repeat) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, repeat.items[0], 0, 1);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[0], 0, 1);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
};
ArrayVirtualRepeatStrategy.prototype.instanceChanged = function instanceChanged(repeat, items) {
@@ -29,27 +56,25 @@ define(['exports', 'aurelia-templating-resources/array-repeat-strategy', 'aureli
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceChanged = function _standardProcessInstanceChanged(repeat, items) {
for (var i = 1, ii = repeat._viewsLength; i < ii; ++i) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, items[i], i, ii);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[i], i, ii);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype._inPlaceProcessItems = function _inPlaceProcessItems(repeat, items) {
var itemsLength = items.length;
- var viewsLength = repeat.viewSlot.children.length;
+ var viewsLength = repeat.viewCount();
var first = repeat._getIndexOfFirstView();
while (viewsLength > repeat._viewsLength) {
viewsLength--;
- repeat.viewSlot.removeAt(viewsLength, true);
+ repeat.removeView(viewsLength, true);
}
var local = repeat.local;
for (var i = 0; i < viewsLength; i++) {
- var view = repeat.viewSlot.children[i];
+ var view = repeat.view(i);
var last = i === itemsLength - 1;
var middle = i !== 0 && !last;
@@ -60,166 +85,193 @@ define(['exports', 'aurelia-templating-resources/array-repeat-strategy', 'aureli
view.bindingContext[local] = items[i + first];
view.overrideContext.$middle = middle;
view.overrideContext.$last = last;
- var j = view.bindings.length;
- while (j--) {
- _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding(view.bindings[j]);
- }
- j = view.controllers.length;
- while (j--) {
- var k = view.controllers[j].boundProperties.length;
- while (k--) {
- var binding = view.controllers[j].boundProperties[k].binding;
- _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding(binding);
- }
- }
+ repeat.updateBindings(view);
}
- for (var i = viewsLength; i < repeat._viewsLength; i++) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, items[i], i, itemsLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var minLength = Math.min(repeat._viewsLength, items.length);
+ for (var _i = viewsLength; _i < minLength; _i++) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[_i], _i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype.instanceMutated = function instanceMutated(repeat, array, splices) {
- this._updateViews(repeat, repeat.items, splices);
+ this._standardProcessInstanceMutated(repeat, array, splices);
};
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceMutated = function _standardProcessInstanceMutated(repeat, array, splices) {
- var _this = this;
+ var _this2 = this;
+
+ if (repeat.__queuedSplices) {
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var _splices$i = splices[i];
+ var index = _splices$i.index;
+ var removed = _splices$i.removed;
+ var addedCount = _splices$i.addedCount;
+
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ var maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ (function () {
+ var queuedSplices = repeat.__queuedSplices = [];
+
+ var runQueuedSplices = function runQueuedSplices() {
+ if (!queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ var nextPromise = _this2._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ })();
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._runSplices = function _runSplices(repeat, array, splices) {
+ var _this3 = this;
var removeDelta = 0;
- var viewSlot = repeat.viewSlot;
var rmPromises = [];
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var removed = splice.removed;
- var viewIndex = this._getViewIndex(repeat, viewSlot, splice.index);
- if (viewIndex >= 0) {
- for (var j = 0, jj = removed.length; j < jj; ++j) {
- var viewOrPromise = viewSlot.removeAt(viewIndex + removeDelta + rmPromises.length, true);
-
- var _length = viewSlot.children.length;
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, repeat.items[_length], _length, repeat.items.length);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.isAttached = false;
- repeat.viewSlot.add(view);
- repeat.viewSlot.isAttached = true;
-
- if (viewOrPromise instanceof Promise) {
- rmPromises.push(viewOrPromise);
- }
+ for (var j = 0, jj = removed.length; j < jj; ++j) {
+ var viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
}
- removeDelta -= splice.addedCount;
}
+ removeDelta -= splice.addedCount;
}
if (rmPromises.length > 0) {
- Promise.all(rmPromises).then(function () {
- _this._handleAddedSplices(repeat, array, splices);
- _this._updateViews(repeat, array, splices);
+ return Promise.all(rmPromises).then(function () {
+ _this3._handleAddedSplices(repeat, array, splices);
+ (0, _utilities.updateVirtualOverrideContexts)(repeat, 0);
});
- } else {
- this._handleAddedSplices(repeat, array, splices);
- this._updateViews(repeat, array, splices);
}
+ this._handleAddedSplices(repeat, array, splices);
+ (0, _utilities.updateVirtualOverrideContexts)(repeat, 0);
};
- ArrayVirtualRepeatStrategy.prototype._updateViews = function _updateViews(repeat, items, splices) {
- var totalAdded = 0;
- var totalRemoved = 0;
- repeat.items = items;
-
- for (var i = 0, ii = splices.length; i < ii; ++i) {
- var splice = splices[0];
- totalAdded += splice.addedCount;
- totalRemoved += splice.removed.length;
+ ArrayVirtualRepeatStrategy.prototype._removeViewAt = function _removeViewAt(repeat, collectionIndex, returnToCache) {
+ var viewOrPromise = void 0;
+ var view = void 0;
+ var viewSlot = repeat.viewSlot;
+ var viewCount = repeat.viewCount();
+ var viewAddIndex = void 0;
+
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ var collectionAddIndex = void 0;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ var data = repeat.items[collectionAddIndex];
+ if (data) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ (0, _utilities.rebindAndMoveView)(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
}
- var index = repeat._getIndexOfFirstView() - totalRemoved;
-
- if (index < 0) {
- index = 0;
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(function () {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
}
- var viewSlot = repeat.viewSlot;
-
- for (var i = 0, ii = viewSlot.children.length; i < ii; ++i) {
- var view = viewSlot.children[i];
- var nextIndex = index + i;
- var itemsLength = items.length;
- if (nextIndex <= itemsLength - 1) {
- view.bindingContext[repeat.local] = items[nextIndex];
- _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext(view.overrideContext, nextIndex, itemsLength);
- }
- }
+ repeat._adjustBufferHeights();
+ };
- var bufferDelta = repeat.itemHeight * totalAdded + repeat.itemHeight * -totalRemoved;
+ ArrayVirtualRepeatStrategy.prototype._isIndexBeforeViewSlot = function _isIndexBeforeViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ };
- if (repeat._bottomBufferHeight + bufferDelta < 0) {
- repeat._topBufferHeight = repeat._topBufferHeight + bufferDelta;
- } else {
- repeat._bottomBufferHeight = repeat._bottomBufferHeight + bufferDelta;
- }
+ ArrayVirtualRepeatStrategy.prototype._isIndexAfterViewSlot = function _isIndexAfterViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ };
- if (repeat._bottomBufferHeight > 0) {
- repeat.isLastIndex = false;
+ ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
+ if (repeat.viewCount() === 0) {
+ return -1;
}
- repeat._adjustBufferHeights();
+ var topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
};
ArrayVirtualRepeatStrategy.prototype._handleAddedSplices = function _handleAddedSplices(repeat, array, splices) {
- var spliceIndexLow = undefined;
var arrayLength = array.length;
+ var viewSlot = repeat.viewSlot;
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var addIndex = splice.index;
var end = splice.index + splice.addedCount;
-
- if (typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index) {
- spliceIndexLow = addIndex;
- }
-
for (; addIndex < end; ++addIndex) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.insert(addIndex, view);
+ var hasDistanceToBottomViewPort = (0, _utilities.getElementDistanceToBottomViewPort)(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || !this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex) || hasDistanceToBottomViewPort) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
}
}
-
- return spliceIndexLow;
- };
-
- ArrayVirtualRepeatStrategy.prototype._isIndexInDom = function _isIndexInDom(viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return false;
- }
-
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var indexHi = viewSlot.children[viewSlot.children.length - 1].overrideContext.$index;
-
- return index >= indexLow && index <= indexHi;
- };
-
- ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return -1;
- }
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var viewIndex = index - indexLow;
- if (viewIndex > repeat._viewsLength - 1) {
- viewIndex = -1;
- }
- return viewIndex;
+ repeat._adjustBufferHeights();
};
return ArrayVirtualRepeatStrategy;
- })(_aureliaTemplatingResourcesArrayRepeatStrategy.ArrayRepeatStrategy);
-
- exports.ArrayVirtualRepeatStrategy = ArrayVirtualRepeatStrategy;
+ }(_arrayRepeatStrategy.ArrayRepeatStrategy);
});
\ No newline at end of file
diff --git a/dist/amd/aurelia-ui-virtualization.d.ts b/dist/amd/aurelia-ui-virtualization.d.ts
new file mode 100644
index 0000000..cc50ca3
--- /dev/null
+++ b/dist/amd/aurelia-ui-virtualization.d.ts
@@ -0,0 +1,131 @@
+declare module 'aurelia-ui-virtualization' {
+ import {
+ updateOverrideContext,
+ createFullOverrideContext,
+ getItemsSourceExpression,
+ isOneTime,
+ unwrapExpression,
+ updateOneTimeBinding
+ } from 'aurelia-templating-resources/repeat-utilities';
+ import {
+ ArrayRepeatStrategy
+ } from 'aurelia-templating-resources/array-repeat-strategy';
+ import {
+ RepeatStrategyLocator
+ } from 'aurelia-templating-resources/repeat-strategy-locator';
+ import {
+ inject
+ } from 'aurelia-dependency-injection';
+ import {
+ ObserverLocator
+ } from 'aurelia-binding';
+ import {
+ BoundViewFactory,
+ ViewSlot,
+ TargetInstruction,
+ customAttribute,
+ bindable,
+ templateController
+ } from 'aurelia-templating';
+ import {
+ AbstractRepeater
+ } from 'aurelia-templating-resources';
+ import {
+ viewsRequireLifecycle
+ } from 'aurelia-templating-resources/analyze-view-factory';
+ export function calcOuterHeight(element: any): any;
+ export function insertBeforeNode(view: any, bottomBuffer: any): any;
+
+ /**
+ * Update the override context.
+ * @param startIndex index in collection where to start updating.
+ */
+ export function updateVirtualOverrideContexts(repeat: any, startIndex: any): any;
+ export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void;
+ export function getStyleValue(element: any, style: any): any;
+ export function getElementDistanceToBottomViewPort(element: any): any;
+
+ /**
+ * A strategy for repeating a template over an array.
+ */
+ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+
+ // create first item to calculate the heights
+ createFirstItem(repeat: any): any;
+
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat: any, items: any): any;
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat: any, array: any, splices: any): any;
+ }
+ export class ViewStrategyLocator {
+ getStrategy(element: any): any;
+ }
+ export class TableStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class DefaultStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor();
+ }
+ export class VirtualRepeat extends AbstractRepeater {
+ _first: any;
+ _previousFirst: any;
+ _viewsLength: any;
+ _lastRebind: any;
+ _topBufferHeight: any;
+ _bottomBufferHeight: any;
+ _bufferSize: any;
+ _scrollingDown: any;
+ _scrollingUp: any;
+ _switchedDirection: any;
+ _isAttached: any;
+ _ticking: any;
+ _fixedHeightContainer: any;
+ _hasCalculatedSizes: any;
+ _isAtTop: any;
+ items: any;
+ local: any;
+ constructor(element: any, viewFactory: any, instruction: any, viewSlot: any, observerLocator: any, strategyLocator: any, viewStrategyLocator: any);
+ attached(): any;
+ bind(bindingContext: any, overrideContext: any): any;
+ call(context: any, changes: any): any;
+ detached(): any;
+ itemsChanged(): any;
+ unbind(): any;
+ handleCollectionMutated(collection: any, changes: any): any;
+ handleInnerCollectionMutated(collection: any, changes: any): any;
+
+ // @override AbstractRepeater
+ viewCount(): any;
+ views(): any;
+ view(index: any): any;
+ addView(bindingContext: any, overrideContext: any): any;
+ insertView(index: any, bindingContext: any, overrideContext: any): any;
+ removeAllViews(returnToCache: any, skipAnimation: any): any;
+ removeView(index: any, returnToCache: any, skipAnimation: any): any;
+ updateBindings(view: View): any;
+ }
+}
\ No newline at end of file
diff --git a/dist/amd/index.js b/dist/amd/index.js
index 5882b6a..fd730f6 100644
--- a/dist/amd/index.js
+++ b/dist/amd/index.js
@@ -1,13 +1,14 @@
-define(['exports', './virtual-repeat', './virtual-list'], function (exports, _virtualRepeat, _virtualList) {
+define(['exports', './virtual-repeat'], function (exports, _virtualRepeat) {
'use strict';
- exports.__esModule = true;
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.VirtualRepeat = undefined;
exports.configure = configure;
-
function configure(config) {
- config.globalResources('./virtual-repeat', './virtual-list');
+ config.globalResources('./virtual-repeat');
}
exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
- exports.VirtualList = _virtualList.VirtualList;
});
\ No newline at end of file
diff --git a/dist/amd/utilities.js b/dist/amd/utilities.js
index e705748..f259ba3 100644
--- a/dist/amd/utilities.js
+++ b/dist/amd/utilities.js
@@ -1,41 +1,73 @@
-define(['exports'], function (exports) {
+define(['exports', 'aurelia-templating-resources/repeat-utilities'], function (exports, _repeatUtilities) {
'use strict';
- exports.__esModule = true;
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
exports.calcOuterHeight = calcOuterHeight;
- exports.calcScrollHeight = calcScrollHeight;
exports.insertBeforeNode = insertBeforeNode;
-
+ exports.updateVirtualOverrideContexts = updateVirtualOverrideContexts;
+ exports.rebindAndMoveView = rebindAndMoveView;
+ exports.getStyleValue = getStyleValue;
+ exports.getElementDistanceToBottomViewPort = getElementDistanceToBottomViewPort;
function calcOuterHeight(element) {
- var height;
+ var height = void 0;
height = element.getBoundingClientRect().height;
height += getStyleValue(element, 'marginTop');
height += getStyleValue(element, 'marginBottom');
return height;
}
- function calcScrollHeight(element) {
- var height;
- height = element.getBoundingClientRect().height;
- height -= getStyleValue(element, 'borderTopWidth');
- height -= getStyleValue(element, 'borderBottomWidth');
- return height;
- }
-
- function insertBeforeNode(view, scrollView, node) {
+ function insertBeforeNode(view, bottomBuffer) {
var viewStart = view.firstChild;
var element = viewStart.nextSibling;
var viewEnd = view.lastChild;
+ var parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+ }
- scrollView.insertBefore(viewEnd, node);
- scrollView.insertBefore(element, viewEnd);
- scrollView.insertBefore(viewStart, element);
+ function updateVirtualOverrideContexts(repeat, startIndex) {
+ var views = repeat.viewSlot.children;
+ var viewLength = views.length;
+ var collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ var delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ (0, _repeatUtilities.updateOverrideContext)(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+ }
+
+ function rebindAndMoveView(repeat, view, index, moveToBottom) {
+ var items = repeat.items;
+ var viewSlot = repeat.viewSlot;
+ (0, _repeatUtilities.updateOverrideContext)(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
}
function getStyleValue(element, style) {
- var currentStyle, styleValue;
+ var currentStyle = void 0;
+ var styleValue = void 0;
currentStyle = element.currentStyle || window.getComputedStyle(element);
- styleValue = parseInt(currentStyle[style]);
+ styleValue = parseInt(currentStyle[style], 10);
return Number.isNaN(styleValue) ? 0 : styleValue;
}
+
+ function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
+ }
});
\ No newline at end of file
diff --git a/dist/amd/view-strategy.js b/dist/amd/view-strategy.js
index 1e2ffdf..1b4d8db 100644
--- a/dist/amd/view-strategy.js
+++ b/dist/amd/view-strategy.js
@@ -62,9 +62,9 @@ define(['exports', './utilities'], function (exports, _utilities) {
return buffer;
};
- TableStrategy.prototype.removeBufferElements = function removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer.parentElement);
- scrollList.removeChild(bottomBuffer.parentElement);
+ TableStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
};
return TableStrategy;
@@ -84,7 +84,9 @@ define(['exports', './utilities'], function (exports, _utilities) {
};
DefaultStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- (0, _utilities.insertBeforeNode)(view, bottomBuffer);
+ var previousSibling = bottomBuffer.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ (0, _utilities.insertBeforeNode)(view, referenceNode);
};
DefaultStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
@@ -104,8 +106,8 @@ define(['exports', './utilities'], function (exports, _utilities) {
};
DefaultStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
- element.removeChild(topBuffer);
- element.removeChild(bottomBuffer);
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
};
return DefaultStrategy;
diff --git a/dist/amd/virtual-list.html b/dist/amd/virtual-list.html
deleted file mode 100644
index fcba809..0000000
--- a/dist/amd/virtual-list.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/dist/amd/virtual-list.js b/dist/amd/virtual-list.js
deleted file mode 100644
index 2a64896..0000000
--- a/dist/amd/virtual-list.js
+++ /dev/null
@@ -1,36 +0,0 @@
-define(['exports', 'aurelia-templating'], function (exports, _aureliaTemplating) {
- 'use strict';
-
- exports.__esModule = true;
-
- var _createDecoratedClass = (function () { function defineProperties(target, descriptors, initializers) { for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } if (descriptor.initializer !== undefined) { initializers[key] = descriptor; continue; } } Object.defineProperty(target, key, descriptor); } } return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); return Constructor; }; })();
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
- function _defineDecoratedPropertyDescriptor(target, key, descriptors) { var _descriptor = descriptors[key]; if (!_descriptor) return; var descriptor = {}; for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; descriptor.value = descriptor.initializer ? descriptor.initializer.call(target) : undefined; Object.defineProperty(target, key, descriptor); }
-
- var VirtualList = (function () {
- var _instanceInitializers = {};
-
- function VirtualList() {
- _classCallCheck(this, VirtualList);
-
- _defineDecoratedPropertyDescriptor(this, 'items', _instanceInitializers);
- }
-
- VirtualList.prototype.bind = function bind(bindingContext, overrideContext) {
- this.$parent = bindingContext;
- };
-
- _createDecoratedClass(VirtualList, [{
- key: 'items',
- decorators: [_aureliaTemplating.bindable],
- initializer: null,
- enumerable: true
- }], null, _instanceInitializers);
-
- return VirtualList;
- })();
-
- exports.VirtualList = VirtualList;
-});
\ No newline at end of file
diff --git a/dist/amd/virtual-repeat-strategy-locator.js b/dist/amd/virtual-repeat-strategy-locator.js
index 9aa7552..ca4570d 100644
--- a/dist/amd/virtual-repeat-strategy-locator.js
+++ b/dist/amd/virtual-repeat-strategy-locator.js
@@ -1,29 +1,58 @@
-define(['exports', 'aurelia-templating-resources/repeat-strategy-locator', './array-virtual-repeat-strategy'], function (exports, _aureliaTemplatingResourcesRepeatStrategyLocator, _arrayVirtualRepeatStrategy) {
+define(['exports', 'aurelia-templating-resources/repeat-strategy-locator', './array-virtual-repeat-strategy'], function (exports, _repeatStrategyLocator, _arrayVirtualRepeatStrategy) {
'use strict';
- exports.__esModule = true;
+ Object.defineProperty(exports, "__esModule", {
+ value: true
+ });
+ exports.VirtualRepeatStrategyLocator = undefined;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
- function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
- var VirtualRepeatStrategyLocator = (function (_RepeatStrategyLocator) {
- _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocator);
+ var VirtualRepeatStrategyLocator = exports.VirtualRepeatStrategyLocator = function (_RepeatStrategyLocato) {
+ _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocato);
function VirtualRepeatStrategyLocator() {
_classCallCheck(this, VirtualRepeatStrategyLocator);
- _RepeatStrategyLocator.call(this);
- this.matchers = [];
- this.strategies = [];
+ var _this = _possibleConstructorReturn(this, _RepeatStrategyLocato.call(this));
- this.addStrategy(function (items) {
+ _this.matchers = [];
+ _this.strategies = [];
+
+ _this.addStrategy(function (items) {
return items instanceof Array;
}, new _arrayVirtualRepeatStrategy.ArrayVirtualRepeatStrategy());
+ return _this;
}
return VirtualRepeatStrategyLocator;
- })(_aureliaTemplatingResourcesRepeatStrategyLocator.RepeatStrategyLocator);
-
- exports.VirtualRepeatStrategyLocator = VirtualRepeatStrategyLocator;
+ }(_repeatStrategyLocator.RepeatStrategyLocator);
});
\ No newline at end of file
diff --git a/dist/amd/virtual-repeat.js b/dist/amd/virtual-repeat.js
index 3f1d129..7bb4acb 100644
--- a/dist/amd/virtual-repeat.js
+++ b/dist/amd/virtual-repeat.js
@@ -1,4 +1,4 @@
-define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-templating', 'aurelia-templating-resources/repeat-utilities', 'aurelia-templating-resources/analyze-view-factory', './utilities', './virtual-repeat-strategy-locator', './view-strategy'], function (exports, _aureliaDependencyInjection, _aureliaBinding, _aureliaTemplating, _repeatUtilities, _analyzeViewFactory, _utilities, _virtualRepeatStrategyLocator, _viewStrategy) {
+define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-templating', 'aurelia-templating-resources', 'aurelia-templating-resources/repeat-utilities', 'aurelia-templating-resources/analyze-view-factory', './utilities', './virtual-repeat-strategy-locator', './view-strategy'], function (exports, _aureliaDependencyInjection, _aureliaBinding, _aureliaTemplating, _aureliaTemplatingResources, _repeatUtilities, _analyzeViewFactory, _utilities, _virtualRepeatStrategyLocator, _viewStrategy) {
'use strict';
Object.defineProperty(exports, "__esModule", {
@@ -22,6 +22,30 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
}
}
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
var desc = {};
Object['ke' + 'ys'](descriptor).forEach(function (key) {
@@ -57,44 +81,51 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
- var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec2 = (0, _aureliaDependencyInjection.inject)(Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaBinding.ObserverLocator, _virtualRepeatStrategyLocator.VirtualRepeatStrategyLocator, _viewStrategy.ViewStrategyLocator), _dec(_class = (0, _aureliaTemplating.templateController)(_class = _dec2(_class = (_class2 = function () {
+ var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec2 = (0, _aureliaDependencyInjection.inject)(Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaBinding.ObserverLocator, _virtualRepeatStrategyLocator.VirtualRepeatStrategyLocator, _viewStrategy.ViewStrategyLocator), _dec(_class = (0, _aureliaTemplating.templateController)(_class = _dec2(_class = (_class2 = function (_AbstractRepeater) {
+ _inherits(VirtualRepeat, _AbstractRepeater);
+
function VirtualRepeat(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
_classCallCheck(this, VirtualRepeat);
- this._first = 0;
- this._previousFirst = 0;
- this._viewsLength = 0;
- this._lastRebind = 0;
- this._topBufferHeight = 0;
- this._bottomBufferHeight = 0;
- this._bufferSize = 5;
- this._scrollingDown = false;
- this._scrollingUp = false;
- this._switchedDirection = false;
- this._isAttached = false;
- this._ticking = false;
- this._fixedHeightContainer = false;
- this._hasCalculatedSizes = false;
-
- _initDefineProp(this, 'items', _descriptor, this);
-
- _initDefineProp(this, 'local', _descriptor2, this);
-
- this.element = element;
- this.viewFactory = viewFactory;
- this.instruction = instruction;
- this.viewSlot = viewSlot;
- this.observerLocator = observerLocator;
- this.strategyLocator = strategyLocator;
- this.viewStrategyLocator = viewStrategyLocator;
- this.local = 'item';
- this.sourceExpression = (0, _repeatUtilities.getItemsSourceExpression)(this.instruction, 'virtual-repeat.for');
- this.isOneTime = (0, _repeatUtilities.isOneTime)(this.sourceExpression);
- this.viewsRequireLifecycle = (0, _analyzeViewFactory.viewsRequireLifecycle)(viewFactory);
+ var _this = _possibleConstructorReturn(this, _AbstractRepeater.call(this, {
+ local: 'item',
+ viewsRequireLifecycle: (0, _analyzeViewFactory.viewsRequireLifecycle)(viewFactory)
+ }));
+
+ _this._first = 0;
+ _this._previousFirst = 0;
+ _this._viewsLength = 0;
+ _this._lastRebind = 0;
+ _this._topBufferHeight = 0;
+ _this._bottomBufferHeight = 0;
+ _this._bufferSize = 5;
+ _this._scrollingDown = false;
+ _this._scrollingUp = false;
+ _this._switchedDirection = false;
+ _this._isAttached = false;
+ _this._ticking = false;
+ _this._fixedHeightContainer = false;
+ _this._hasCalculatedSizes = false;
+ _this._isAtTop = true;
+
+ _initDefineProp(_this, 'items', _descriptor, _this);
+
+ _initDefineProp(_this, 'local', _descriptor2, _this);
+
+ _this.element = element;
+ _this.viewFactory = viewFactory;
+ _this.instruction = instruction;
+ _this.viewSlot = viewSlot;
+ _this.observerLocator = observerLocator;
+ _this.strategyLocator = strategyLocator;
+ _this.viewStrategyLocator = viewStrategyLocator;
+ _this.sourceExpression = (0, _repeatUtilities.getItemsSourceExpression)(_this.instruction, 'virtual-repeat.for');
+ _this.isOneTime = (0, _repeatUtilities.isOneTime)(_this.sourceExpression);
+ return _this;
}
VirtualRepeat.prototype.attached = function attached() {
- var _this = this;
+ var _this2 = this;
this._isAttached = true;
var element = this.element;
@@ -104,7 +135,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
this.itemsChanged();
this.scrollListener = function () {
- return _this._onScroll();
+ return _this2._onScroll();
};
var containerStyle = this.scrollContainer.style;
if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
@@ -116,14 +147,8 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
};
VirtualRepeat.prototype.bind = function bind(bindingContext, overrideContext) {
- var _this2 = this;
-
this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
this._itemsLength = this.items.length;
-
- window.onresize = function () {
- _this2._handleResize();
- };
};
VirtualRepeat.prototype.call = function call(context, changes) {
@@ -131,8 +156,6 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
};
VirtualRepeat.prototype.detached = function detached() {
- window.onresize = null;
-
this.scrollContainer.removeEventListener('scroll', this.scrollListener);
this._first = 0;
this._previousFirst = 0;
@@ -150,7 +173,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
this.isLastIndex = false;
this.scrollContainer = null;
this.scrollContainerHeight = null;
- this.viewSlot.removeAll(true);
+ this.removeAllViews(true);
if (this.scrollHandler) {
this.scrollHandler.dispose();
}
@@ -230,14 +253,17 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
var scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
this._first = Math.floor(scrollTop / itemHeight);
this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
this._checkScrolling();
- if (this._scrollingDown && (this._hasScrolledDownTheBuffer() || this._switchedDirection && this._hasScrolledDownTheBufferFromTop())) {
+ if (this._scrollingDown) {
var viewsToMove = this._first - this._lastRebind;
if (this._switchedDirection) {
- viewsToMove = this.isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
}
- this.isAtTop = false;
+ this._isAtTop = false;
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
@@ -247,53 +273,32 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
if (this._bottomBufferHeight >= 0) {
this._adjustBufferHeights();
}
- } else if (this._scrollingUp && (this._hasScrolledUpTheBuffer() || this._switchedDirection && this._hasScrolledUpTheBufferFromBottom())) {
- var _viewsToMove = this._lastRebind - this._first;
- if (this._switchedDirection) {
- if (this.isLastIndex) {
- _viewsToMove = this.items.length - this._first - this.elementsInView;
- } else {
- _viewsToMove = this._bufferSize - (this._first - this._lastRebind);
- }
- }
- this.isLastIndex = false;
- this._lastRebind = this._first;
- var _movedViewsCount = this._moveViews(_viewsToMove);
- this.movedViewsCount = _movedViewsCount;
- var _adjustHeight = _movedViewsCount < _viewsToMove ? this._topBufferHeight : itemHeight * _movedViewsCount;
- this._switchedDirection = false;
- this._topBufferHeight = this._topBufferHeight - _adjustHeight;
- this._bottomBufferHeight = this._bottomBufferHeight + _adjustHeight;
- if (this._topBufferHeight >= 0) {
- this._adjustBufferHeights();
+ } else if (this._scrollingUp) {
+ var _viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ _viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ _viewsToMove = this._bufferSize - (this._first - this._lastRebind);
}
}
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ var _movedViewsCount = this._moveViews(_viewsToMove);
+ this.movedViewsCount = _movedViewsCount;
+ var _adjustHeight = _movedViewsCount < _viewsToMove ? this._topBufferHeight : itemHeight * _movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - _adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + _adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
this._previousFirst = this._first;
this._ticking = false;
};
- VirtualRepeat.prototype._handleResize = function _handleResize() {
- var children = this.viewSlot.children;
- var childrenLength = children.length;
- var overrideContext = void 0;
- var view = void 0;
- var addIndex = void 0;
-
- this.scrollContainerHeight = calcScrollHeight(this.scrollContainer);
- this._viewsLength = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
-
- if (this._viewsLength > childrenLength) {
- addIndex = children[childrenLength - 1].overrideContext.$index + 1;
- overrideContext = createFullOverrideContext(this, this.items[addIndex], addIndex, this.items.length);
- view = this.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- this.viewSlot.insert(childrenLength, view);
- } else if (this._viewsLength < childrenLength) {
- this._viewsLength = childrenLength;
- }
- };
-
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -304,7 +309,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
this._switchedDirection = false;
}
this._isScrolling = true;
- } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this.isAtTop)) {
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
if (!this._scrollingUp) {
this._scrollingDown = false;
this._scrollingUp = true;
@@ -318,24 +323,6 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
}
};
- VirtualRepeat.prototype._hasScrolledDownTheBuffer = function _hasScrolledDownTheBuffer() {
- var atBottom = this._first + this._viewsLength >= this.items.length;
- var itemsAddedWhileAtBottom = atBottom && this._first > this._lastRebind;
- return this._first - this._lastRebind >= this._bufferSize || itemsAddedWhileAtBottom;
- };
-
- VirtualRepeat.prototype._hasScrolledDownTheBufferFromTop = function _hasScrolledDownTheBufferFromTop() {
- return this._first - this._bufferSize > 0;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBuffer = function _hasScrolledUpTheBuffer() {
- return this._lastRebind - this._first >= this._bufferSize;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBufferFromBottom = function _hasScrolledUpTheBufferFromBottom() {
- return this._first + this._bufferSize < this.items.length;
- };
-
VirtualRepeat.prototype._adjustBufferHeights = function _adjustBufferHeights() {
this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
@@ -358,35 +345,33 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5.isAtTop;
+ return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
};
- var viewSlot = this.viewSlot;
- var childrenLength = viewSlot.children.length;
+ var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
var items = this.items;
var index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
var i = 0;
while (i < length && !isAtFirstOrLastIndex()) {
- var view = viewSlot.children[viewIndex];
+ var view = this.view(viewIndex);
var nextIndex = getNextIndex(index, i);
this.isLastIndex = nextIndex >= items.length - 1;
- this.isAtTop = nextIndex <= 0;
- if (!isAtFirstOrLastIndex()) {
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
(0, _utilities.rebindAndMoveView)(this, view, nextIndex, this._scrollingDown);
i++;
}
}
+
return length - (length - i);
};
VirtualRepeat.prototype._getIndexOfLastView = function _getIndexOfLastView() {
- var children = this.viewSlot.children;
- return children[children.length - 1].overrideContext.$index;
+ return this.view(this.viewCount() - 1).overrideContext.$index;
};
VirtualRepeat.prototype._getIndexOfFirstView = function _getIndexOfFirstView() {
- var children = this.viewSlot.children;
- return children[0] ? children[0].overrideContext.$index : -1;
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
};
VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights(itemsLength) {
@@ -395,7 +380,7 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
}
this._hasCalculatedSizes = true;
this._itemsLength = itemsLength;
- var firstViewElement = this.viewSlot.children[0].firstChild.nextElementSibling;
+ var firstViewElement = this.view(0).firstChild.nextElementSibling;
this.itemHeight = (0, _utilities.calcOuterHeight)(firstViewElement);
if (this.itemHeight <= 0) {
throw new Error('Could not calculate item height');
@@ -455,8 +440,55 @@ define(['exports', 'aurelia-dependency-injection', 'aurelia-binding', 'aurelia-t
}
};
+ VirtualRepeat.prototype.viewCount = function viewCount() {
+ return this.viewSlot.children.length;
+ };
+
+ VirtualRepeat.prototype.views = function views() {
+ return this.viewSlot.children;
+ };
+
+ VirtualRepeat.prototype.view = function view(index) {
+ return this.viewSlot.children[index];
+ };
+
+ VirtualRepeat.prototype.addView = function addView(bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ };
+
+ VirtualRepeat.prototype.insertView = function insertView(index, bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ };
+
+ VirtualRepeat.prototype.removeAllViews = function removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.removeView = function removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.updateBindings = function updateBindings(view) {
+ var j = view.bindings.length;
+ while (j--) {
+ (0, _repeatUtilities.updateOneTimeBinding)(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ var k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ var binding = view.controllers[j].boundProperties[k].binding;
+ (0, _repeatUtilities.updateOneTimeBinding)(binding);
+ }
+ }
+ };
+
return VirtualRepeat;
- }(), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [_aureliaTemplating.bindable], {
+ }(_aureliaTemplatingResources.AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [_aureliaTemplating.bindable], {
enumerable: true,
initializer: null
}), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, 'local', [_aureliaTemplating.bindable], {
diff --git a/dist/aurelia-ui-virtualization.d.ts b/dist/aurelia-ui-virtualization.d.ts
new file mode 100644
index 0000000..cc50ca3
--- /dev/null
+++ b/dist/aurelia-ui-virtualization.d.ts
@@ -0,0 +1,131 @@
+declare module 'aurelia-ui-virtualization' {
+ import {
+ updateOverrideContext,
+ createFullOverrideContext,
+ getItemsSourceExpression,
+ isOneTime,
+ unwrapExpression,
+ updateOneTimeBinding
+ } from 'aurelia-templating-resources/repeat-utilities';
+ import {
+ ArrayRepeatStrategy
+ } from 'aurelia-templating-resources/array-repeat-strategy';
+ import {
+ RepeatStrategyLocator
+ } from 'aurelia-templating-resources/repeat-strategy-locator';
+ import {
+ inject
+ } from 'aurelia-dependency-injection';
+ import {
+ ObserverLocator
+ } from 'aurelia-binding';
+ import {
+ BoundViewFactory,
+ ViewSlot,
+ TargetInstruction,
+ customAttribute,
+ bindable,
+ templateController
+ } from 'aurelia-templating';
+ import {
+ AbstractRepeater
+ } from 'aurelia-templating-resources';
+ import {
+ viewsRequireLifecycle
+ } from 'aurelia-templating-resources/analyze-view-factory';
+ export function calcOuterHeight(element: any): any;
+ export function insertBeforeNode(view: any, bottomBuffer: any): any;
+
+ /**
+ * Update the override context.
+ * @param startIndex index in collection where to start updating.
+ */
+ export function updateVirtualOverrideContexts(repeat: any, startIndex: any): any;
+ export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void;
+ export function getStyleValue(element: any, style: any): any;
+ export function getElementDistanceToBottomViewPort(element: any): any;
+
+ /**
+ * A strategy for repeating a template over an array.
+ */
+ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+
+ // create first item to calculate the heights
+ createFirstItem(repeat: any): any;
+
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat: any, items: any): any;
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat: any, array: any, splices: any): any;
+ }
+ export class ViewStrategyLocator {
+ getStrategy(element: any): any;
+ }
+ export class TableStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class DefaultStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor();
+ }
+ export class VirtualRepeat extends AbstractRepeater {
+ _first: any;
+ _previousFirst: any;
+ _viewsLength: any;
+ _lastRebind: any;
+ _topBufferHeight: any;
+ _bottomBufferHeight: any;
+ _bufferSize: any;
+ _scrollingDown: any;
+ _scrollingUp: any;
+ _switchedDirection: any;
+ _isAttached: any;
+ _ticking: any;
+ _fixedHeightContainer: any;
+ _hasCalculatedSizes: any;
+ _isAtTop: any;
+ items: any;
+ local: any;
+ constructor(element: any, viewFactory: any, instruction: any, viewSlot: any, observerLocator: any, strategyLocator: any, viewStrategyLocator: any);
+ attached(): any;
+ bind(bindingContext: any, overrideContext: any): any;
+ call(context: any, changes: any): any;
+ detached(): any;
+ itemsChanged(): any;
+ unbind(): any;
+ handleCollectionMutated(collection: any, changes: any): any;
+ handleInnerCollectionMutated(collection: any, changes: any): any;
+
+ // @override AbstractRepeater
+ viewCount(): any;
+ views(): any;
+ view(index: any): any;
+ addView(bindingContext: any, overrideContext: any): any;
+ insertView(index: any, bindingContext: any, overrideContext: any): any;
+ removeAllViews(returnToCache: any, skipAnimation: any): any;
+ removeView(index: any, returnToCache: any, skipAnimation: any): any;
+ updateBindings(view: View): any;
+ }
+}
\ No newline at end of file
diff --git a/dist/aurelia-ui-virtualization.js b/dist/aurelia-ui-virtualization.js
new file mode 100644
index 0000000..49e9bad
--- /dev/null
+++ b/dist/aurelia-ui-virtualization.js
@@ -0,0 +1,783 @@
+import {updateOverrideContext,createFullOverrideContext,getItemsSourceExpression,isOneTime,unwrapExpression,updateOneTimeBinding} from 'aurelia-templating-resources/repeat-utilities';
+import {ArrayRepeatStrategy} from 'aurelia-templating-resources/array-repeat-strategy';
+import {RepeatStrategyLocator} from 'aurelia-templating-resources/repeat-strategy-locator';
+import {inject} from 'aurelia-dependency-injection';
+import {ObserverLocator} from 'aurelia-binding';
+import {BoundViewFactory,ViewSlot,TargetInstruction,customAttribute,bindable,templateController} from 'aurelia-templating';
+import {AbstractRepeater} from 'aurelia-templating-resources';
+import {viewsRequireLifecycle} from 'aurelia-templating-resources/analyze-view-factory';
+
+export function calcOuterHeight(element) {
+ let height;
+ height = element.getBoundingClientRect().height;
+ height += getStyleValue(element, 'marginTop');
+ height += getStyleValue(element, 'marginBottom');
+ return height;
+}
+
+export function insertBeforeNode(view, bottomBuffer) {
+ let viewStart = view.firstChild;
+ let element = viewStart.nextSibling;
+ let viewEnd = view.lastChild;
+ let parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+}
+
+/**
+* Update the override context.
+* @param startIndex index in collection where to start updating.
+*/
+export function updateVirtualOverrideContexts(repeat, startIndex) {
+ let views = repeat.viewSlot.children;
+ let viewLength = views.length;
+ let collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ let delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ updateOverrideContext(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+}
+
+export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void {
+ let items = repeat.items;
+ let viewSlot = repeat.viewSlot;
+ updateOverrideContext(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
+}
+
+export function getStyleValue(element, style) {
+ let currentStyle;
+ let styleValue;
+ currentStyle = element.currentStyle || window.getComputedStyle(element);
+ styleValue = parseInt(currentStyle[style], 10);
+ return Number.isNaN(styleValue) ? 0 : styleValue;
+}
+
+export function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
+}
+
+/**
+* A strategy for repeating a template over an array.
+*/
+export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+ // create first item to calculate the heights
+ createFirstItem(repeat) {
+ let overrideContext = createFullOverrideContext(repeat, repeat.items[0], 0, 1);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat, items) {
+ this._inPlaceProcessItems(repeat, items);
+ }
+
+ _standardProcessInstanceChanged(repeat, items) {
+ for (let i = 1, ii = repeat._viewsLength; i < ii; ++i) {
+ let overrideContext = createFullOverrideContext(repeat, items[i], i, ii);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ }
+
+ _inPlaceProcessItems(repeat, items) {
+ let itemsLength = items.length;
+ let viewsLength = repeat.viewCount();
+ let first = repeat._getIndexOfFirstView();
+ // remove unneeded views.
+ while (viewsLength > repeat._viewsLength) {
+ viewsLength--;
+ repeat.removeView(viewsLength, true);
+ }
+ // avoid repeated evaluating the property-getter for the "local" property.
+ let local = repeat.local;
+ // re-evaluate bindings on existing views.
+ for (let i = 0; i < viewsLength; i++) {
+ let view = repeat.view(i);
+ let last = i === itemsLength - 1;
+ let middle = i !== 0 && !last;
+ // any changes to the binding context?
+ if (view.bindingContext[local] === items[i + first] && view.overrideContext.$middle === middle && view.overrideContext.$last === last) {
+ // no changes. continue...
+ continue;
+ }
+ // update the binding context and refresh the bindings.
+ view.bindingContext[local] = items[i + first];
+ view.overrideContext.$middle = middle;
+ view.overrideContext.$last = last;
+ repeat.updateBindings(view);
+ }
+ // add new views
+ let minLength = Math.min(repeat._viewsLength, items.length);
+ for (let i = viewsLength; i < minLength; i++) {
+ let overrideContext = createFullOverrideContext(repeat, items[i], i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ }
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat, array, splices) {
+ this._standardProcessInstanceMutated(repeat, array, splices);
+ }
+
+ _standardProcessInstanceMutated(repeat, array, splices) {
+ if (repeat.__queuedSplices) {
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let {index, removed, addedCount} = splices[i];
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ let maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ let queuedSplices = repeat.__queuedSplices = [];
+
+ let runQueuedSplices = () => {
+ if (! queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ let nextPromise = this._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ }
+ }
+
+ _runSplices(repeat, array, splices) {
+ let removeDelta = 0;
+ let rmPromises = [];
+
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let splice = splices[i];
+ let removed = splice.removed;
+ for (let j = 0, jj = removed.length; j < jj; ++j) {
+ let viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
+ }
+ }
+ removeDelta -= splice.addedCount;
+ }
+
+ if (rmPromises.length > 0) {
+ return Promise.all(rmPromises).then(() => {
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ });
+ }
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ }
+
+ _removeViewAt(repeat, collectionIndex, returnToCache) {
+ let viewOrPromise;
+ let view;
+ let viewSlot = repeat.viewSlot;
+ let viewCount = repeat.viewCount();
+ let viewAddIndex;
+ // index in view slot?
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ // TODO: do not trigger view lifecycle here
+ let collectionAddIndex;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - (repeat.itemHeight);
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - (repeat.itemHeight);
+ }
+ let data = repeat.items[collectionAddIndex];
+ if (data) {
+ let overrideContext = createFullOverrideContext(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - (repeat.itemHeight);
+ rebindAndMoveView(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - (repeat.itemHeight);
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - (repeat.itemHeight);
+ }
+
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(() => {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ }
+
+ repeat._adjustBufferHeights();
+ }
+
+ _isIndexBeforeViewSlot(repeat: VirtualRepeat, viewSlot: ViewSlot, index: number): number {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ }
+
+ _isIndexAfterViewSlot(repeat: VirtualRepeat, viewSlot: ViewSlot, index: number): number {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ }
+
+ _getViewIndex(repeat: VirtualRepeat, viewSlot: ViewSlot, index: number): number {
+ if (repeat.viewCount() === 0) {
+ return -1;
+ }
+
+ let topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
+ }
+
+ _handleAddedSplices(repeat, array, splices) {
+ let arrayLength = array.length;
+ let viewSlot = repeat.viewSlot;
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let splice = splices[i];
+ let addIndex = splice.index;
+ let end = splice.index + splice.addedCount;
+ for (; addIndex < end; ++addIndex) {
+ let hasDistanceToBottomViewPort = getElementDistanceToBottomViewPort(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || (!this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) || hasDistanceToBottomViewPort) {
+ let overrideContext = createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
+ }
+ }
+ repeat._adjustBufferHeights();
+ }
+}
+
+export class ViewStrategyLocator {
+ getStrategy(element) {
+ if (element.parentNode.localName === 'tbody') {
+ return new TableStrategy();
+ }
+ return new DefaultStrategy();
+ }
+}
+
+export class TableStrategy {
+ getScrollContainer(element) {
+ return element.parentNode;
+ }
+
+ moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.parentElement.nextElementSibling.previousSibling);
+ }
+
+ moveViewLast(view, bottomBuffer) {
+ insertBeforeNode(view, bottomBuffer.parentElement);
+ }
+
+ createTopBufferElement(element) {
+ let tr = document.createElement('tr');
+ let buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentElement.insertBefore(tr, element);
+ return buffer;
+ }
+
+ createBottomBufferElement(element) {
+ let tr = document.createElement('tr');
+ let buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentNode.insertBefore(tr, element.nextSibling);
+ return buffer;
+ }
+
+ removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
+ }
+}
+
+export class DefaultStrategy {
+ getScrollContainer(element) {
+ return element.parentNode;
+ }
+
+ moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.nextElementSibling.previousSibling);
+ }
+
+ moveViewLast(view, bottomBuffer) {
+ let previousSibling = bottomBuffer.previousSibling;
+ let referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ insertBeforeNode(view, referenceNode);
+ }
+
+ createTopBufferElement(element) {
+ let elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ let buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentElement.insertBefore(buffer, element);
+ return buffer;
+ }
+
+ createBottomBufferElement(element) {
+ let elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ let buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentNode.insertBefore(buffer, element.nextSibling);
+ return buffer;
+ }
+
+ removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
+ }
+}
+
+export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor() {
+ super();
+ this.matchers = [];
+ this.strategies = [];
+
+ this.addStrategy(items => items instanceof Array, new ArrayVirtualRepeatStrategy());
+ }
+}
+
+@customAttribute('virtual-repeat')
+@templateController
+@inject(Element, BoundViewFactory, TargetInstruction, ViewSlot, ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator)
+export class VirtualRepeat extends AbstractRepeater {
+ _first = 0;
+ _previousFirst = 0;
+ _viewsLength = 0;
+ _lastRebind = 0;
+ _topBufferHeight = 0;
+ _bottomBufferHeight = 0;
+ _bufferSize = 5;
+ _scrollingDown = false;
+ _scrollingUp = false;
+ _switchedDirection = false;
+ _isAttached = false;
+ _ticking = false;
+ _fixedHeightContainer = false;
+ _hasCalculatedSizes = false;
+ _isAtTop = true;
+
+ @bindable items
+ @bindable local
+ constructor(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
+ super({
+ local: 'item',
+ viewsRequireLifecycle: viewsRequireLifecycle(viewFactory)
+ });
+
+ this.element = element;
+ this.viewFactory = viewFactory;
+ this.instruction = instruction;
+ this.viewSlot = viewSlot;
+ this.observerLocator = observerLocator;
+ this.strategyLocator = strategyLocator;
+ this.viewStrategyLocator = viewStrategyLocator;
+ this.sourceExpression = getItemsSourceExpression(this.instruction, 'virtual-repeat.for');
+ this.isOneTime = isOneTime(this.sourceExpression);
+ }
+
+ attached() {
+ this._isAttached = true;
+ let element = this.element;
+ this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
+ this.scrollContainer = this.viewStrategy.getScrollContainer(element);
+ this.topBuffer = this.viewStrategy.createTopBufferElement(element);
+ this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
+ this.itemsChanged();
+ this.scrollListener = () => this._onScroll();
+ let containerStyle = this.scrollContainer.style;
+ if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
+ this._fixedHeightContainer = true;
+ this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ } else {
+ document.addEventListener('scroll', this.scrollListener);
+ }
+ }
+
+ bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext, overrideContext };
+ this._itemsLength = this.items.length;
+ }
+
+ call(context, changes) {
+ this[context](this.items, changes);
+ }
+
+ detached() {
+ this.scrollContainer.removeEventListener('scroll', this.scrollListener);
+ this._first = 0;
+ this._previousFirst = 0;
+ this._viewsLength = 0;
+ this._lastRebind = 0;
+ this._topBufferHeight = 0;
+ this._bottomBufferHeight = 0;
+ this._scrollingDown = false;
+ this._scrollingUp = false;
+ this._switchedDirection = false;
+ this._isAttached = false;
+ this._ticking = false;
+ this._hasCalculatedSizes = false;
+ this.viewStrategy.removeBufferElements(this.element, this.topBuffer, this.bottomBuffer);
+ this.isLastIndex = false;
+ this.scrollContainer = null;
+ this.scrollContainerHeight = null;
+ this.removeAllViews(true);
+ if (this.scrollHandler) {
+ this.scrollHandler.dispose();
+ }
+ this._unsubscribeCollection();
+ }
+
+ itemsChanged() {
+ this._unsubscribeCollection();
+ // still bound?
+ if (!this.scope) {
+ return;
+ }
+ let items = this.items;
+ this.strategy = this.strategyLocator.getStrategy(items);
+ if (items.length > 0) {
+ this.strategy.createFirstItem(this);
+ }
+ this._calcInitialHeights(items.length);
+ if (!this.isOneTime && !this._observeInnerCollection()) {
+ this._observeCollection();
+ }
+
+ this.strategy.instanceChanged(this, items, this._viewsLength);
+ }
+
+ unbind() {
+ this.scope = null;
+ this.items = null;
+ this._itemsLength = null;
+ }
+
+ handleCollectionMutated(collection, changes) {
+ this._handlingMutations = true;
+ this._itemsLength = collection.length;
+ this.strategy.instanceMutated(this, collection, changes);
+ }
+
+ handleInnerCollectionMutated(collection, changes) {
+ // guard against source expressions that have observable side-effects that could
+ // cause an infinite loop- eg a value converter that mutates the source array.
+ if (this.ignoreMutation) {
+ return;
+ }
+ this.ignoreMutation = true;
+ let newItems = this.sourceExpression.evaluate(this.scope, this.lookupFunctions);
+ this.observerLocator.taskQueue.queueMicroTask(() => this.ignoreMutation = false);
+
+ // call itemsChanged...
+ if (newItems === this.items) {
+ // call itemsChanged directly.
+ this.itemsChanged();
+ } else {
+ // call itemsChanged indirectly by assigning the new collection value to
+ // the items property, which will trigger the self-subscriber to call itemsChanged.
+ this.items = newItems;
+ }
+ }
+
+ _onScroll() {
+ if (!this._ticking && !this._handlingMutations) {
+ requestAnimationFrame(() => this._handleScroll());
+ this._ticking = true;
+ }
+
+ if (this._handlingMutations) {
+ this._handlingMutations = false;
+ }
+ }
+
+ _handleScroll() {
+ if (!this._isAttached) {
+ return;
+ }
+ let itemHeight = this.itemHeight;
+ let scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
+ this._first = Math.floor(scrollTop / itemHeight);
+ this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
+ this._checkScrolling();
+ // TODO if and else paths do almost same thing, refactor?
+ if (this._scrollingDown) {
+ let viewsToMove = this._first - this._lastRebind;
+ if (this._switchedDirection) {
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ }
+ this._isAtTop = false;
+ this._lastRebind = this._first;
+ let movedViewsCount = this._moveViews(viewsToMove);
+ let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight + adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
+ if (this._bottomBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ } else if (this._scrollingUp) {
+ let viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ viewsToMove = this._bufferSize - (this._first - this._lastRebind);
+ }
+ }
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ let movedViewsCount = this._moveViews(viewsToMove);
+ this.movedViewsCount = movedViewsCount;
+ let adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
+ this._previousFirst = this._first;
+
+ this._ticking = false;
+ }
+
+ _checkScrolling() {
+ if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
+ if (!this._scrollingDown) {
+ this._scrollingDown = true;
+ this._scrollingUp = false;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
+ if (!this._scrollingUp) {
+ this._scrollingDown = false;
+ this._scrollingUp = true;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else {
+ this._isScrolling = false;
+ }
+ }
+
+ _adjustBufferHeights() {
+ this.topBuffer.setAttribute('style', `height: ${this._topBufferHeight}px`);
+ this.bottomBuffer.setAttribute('style', `height: ${this._bottomBufferHeight}px`);
+ }
+
+ _unsubscribeCollection() {
+ if (this.collectionObserver) {
+ this.collectionObserver.unsubscribe(this.callContext, this);
+ this.collectionObserver = null;
+ this.callContext = null;
+ }
+ }
+
+ _moveViews(length) {
+ let getNextIndex = this._scrollingDown ? (index, i) => index + i : (index, i) => index - i;
+ let isAtFirstOrLastIndex = () => this._scrollingDown ? this.isLastIndex : this._isAtTop;
+ let childrenLength = this.viewCount();
+ let viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
+ let items = this.items;
+ let index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
+ let i = 0;
+ while (i < length && !isAtFirstOrLastIndex()) {
+ let view = this.view(viewIndex);
+ let nextIndex = getNextIndex(index, i);
+ this.isLastIndex = nextIndex >= items.length - 1;
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
+ rebindAndMoveView(this, view, nextIndex, this._scrollingDown);
+ i++;
+ }
+ }
+
+ return length - (length - i);
+ }
+
+ _getIndexOfLastView() {
+ return this.view(this.viewCount() - 1).overrideContext.$index;
+ }
+
+ _getIndexOfFirstView() {
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
+ }
+
+ _calcInitialHeights(itemsLength: number) {
+ if (this._viewsLength > 0 && this._itemsLength === itemsLength || itemsLength <= 0) {
+ return;
+ }
+ this._hasCalculatedSizes = true;
+ this._itemsLength = itemsLength;
+ let firstViewElement = this.view(0).firstChild.nextElementSibling;
+ this.itemHeight = calcOuterHeight(firstViewElement);
+ if (this.itemHeight <= 0) {
+ throw new Error('Could not calculate item height');
+ }
+ this.scrollContainerHeight = this._fixedHeightContainer ? this._calcScrollHeight(this.scrollContainer) : document.documentElement.clientHeight;
+ this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
+ this._viewsLength = (this.elementsInView * 2) + this._bufferSize;
+ this._bottomBufferHeight = this.itemHeight * itemsLength - this.itemHeight * this._viewsLength;
+ if (this._bottomBufferHeight < 0) {
+ this._bottomBufferHeight = 0;
+ }
+ this.bottomBuffer.setAttribute('style', `height: ${this._bottomBufferHeight}px`);
+ this._topBufferHeight = 0;
+ this.topBuffer.setAttribute('style', `height: ${this._topBufferHeight}px`);
+ // TODO This will cause scrolling back to top when swapping collection instances that have different lengths - instead should keep the scroll position
+ this.scrollContainer.scrollTop = 0;
+ this._first = 0;
+ }
+
+ _calcScrollHeight(element) {
+ let height;
+ height = element.getBoundingClientRect().height;
+ height -= getStyleValue(element, 'borderTopWidth');
+ height -= getStyleValue(element, 'borderBottomWidth');
+ return height;
+ }
+
+ _observeInnerCollection() {
+ let items = this._getInnerCollection();
+ let strategy = this.strategyLocator.getStrategy(items);
+ if (!strategy) {
+ return false;
+ }
+ this.collectionObserver = strategy.getCollectionObserver(this.observerLocator, items);
+ if (!this.collectionObserver) {
+ return false;
+ }
+ this.callContext = 'handleInnerCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ return true;
+ }
+
+ _getInnerCollection() {
+ let expression = unwrapExpression(this.sourceExpression);
+ if (!expression) {
+ return null;
+ }
+ return expression.evaluate(this.scope, null);
+ }
+
+ _observeCollection() {
+ let items = this.items;
+ this.collectionObserver = this.strategy.getCollectionObserver(this.observerLocator, items);
+ if (this.collectionObserver) {
+ this.callContext = 'handleCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ }
+ }
+
+ // @override AbstractRepeater
+ viewCount() { return this.viewSlot.children.length; }
+ views() { return this.viewSlot.children; }
+ view(index) { return this.viewSlot.children[index]; }
+
+ addView(bindingContext, overrideContext) {
+ let view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ }
+
+ insertView(index, bindingContext, overrideContext) {
+ let view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ }
+
+ removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ }
+
+ removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ }
+
+ updateBindings(view: View) {
+ let j = view.bindings.length;
+ while (j--) {
+ updateOneTimeBinding(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ let k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ let binding = view.controllers[j].boundProperties[k].binding;
+ updateOneTimeBinding(binding);
+ }
+ }
+ }
+}
diff --git a/dist/commonjs/array-virtual-repeat-strategy.js b/dist/commonjs/array-virtual-repeat-strategy.js
index 0caabe3..59d4f2b 100644
--- a/dist/commonjs/array-virtual-repeat-strategy.js
+++ b/dist/commonjs/array-virtual-repeat-strategy.js
@@ -1,29 +1,34 @@
'use strict';
-exports.__esModule = true;
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.ArrayVirtualRepeatStrategy = undefined;
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _arrayRepeatStrategy = require('aurelia-templating-resources/array-repeat-strategy');
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _repeatUtilities = require('aurelia-templating-resources/repeat-utilities');
-var _aureliaTemplatingResourcesArrayRepeatStrategy = require('aurelia-templating-resources/array-repeat-strategy');
+var _utilities = require('./utilities');
-var _aureliaTemplatingResourcesRepeatUtilities = require('aurelia-templating-resources/repeat-utilities');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-var ArrayVirtualRepeatStrategy = (function (_ArrayRepeatStrategy) {
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var ArrayVirtualRepeatStrategy = exports.ArrayVirtualRepeatStrategy = function (_ArrayRepeatStrategy) {
_inherits(ArrayVirtualRepeatStrategy, _ArrayRepeatStrategy);
function ArrayVirtualRepeatStrategy() {
_classCallCheck(this, ArrayVirtualRepeatStrategy);
- _ArrayRepeatStrategy.apply(this, arguments);
+ return _possibleConstructorReturn(this, _ArrayRepeatStrategy.apply(this, arguments));
}
ArrayVirtualRepeatStrategy.prototype.createFirstItem = function createFirstItem(repeat) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, repeat.items[0], 0, 1);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[0], 0, 1);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
};
ArrayVirtualRepeatStrategy.prototype.instanceChanged = function instanceChanged(repeat, items) {
@@ -32,27 +37,25 @@ var ArrayVirtualRepeatStrategy = (function (_ArrayRepeatStrategy) {
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceChanged = function _standardProcessInstanceChanged(repeat, items) {
for (var i = 1, ii = repeat._viewsLength; i < ii; ++i) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, items[i], i, ii);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[i], i, ii);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype._inPlaceProcessItems = function _inPlaceProcessItems(repeat, items) {
var itemsLength = items.length;
- var viewsLength = repeat.viewSlot.children.length;
+ var viewsLength = repeat.viewCount();
var first = repeat._getIndexOfFirstView();
while (viewsLength > repeat._viewsLength) {
viewsLength--;
- repeat.viewSlot.removeAt(viewsLength, true);
+ repeat.removeView(viewsLength, true);
}
var local = repeat.local;
for (var i = 0; i < viewsLength; i++) {
- var view = repeat.viewSlot.children[i];
+ var view = repeat.view(i);
var last = i === itemsLength - 1;
var middle = i !== 0 && !last;
@@ -63,165 +66,192 @@ var ArrayVirtualRepeatStrategy = (function (_ArrayRepeatStrategy) {
view.bindingContext[local] = items[i + first];
view.overrideContext.$middle = middle;
view.overrideContext.$last = last;
- var j = view.bindings.length;
- while (j--) {
- _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding(view.bindings[j]);
- }
- j = view.controllers.length;
- while (j--) {
- var k = view.controllers[j].boundProperties.length;
- while (k--) {
- var binding = view.controllers[j].boundProperties[k].binding;
- _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding(binding);
- }
- }
+ repeat.updateBindings(view);
}
- for (var i = viewsLength; i < repeat._viewsLength; i++) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, items[i], i, itemsLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var minLength = Math.min(repeat._viewsLength, items.length);
+ for (var _i = viewsLength; _i < minLength; _i++) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[_i], _i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype.instanceMutated = function instanceMutated(repeat, array, splices) {
- this._updateViews(repeat, repeat.items, splices);
+ this._standardProcessInstanceMutated(repeat, array, splices);
};
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceMutated = function _standardProcessInstanceMutated(repeat, array, splices) {
- var _this = this;
+ var _this2 = this;
+
+ if (repeat.__queuedSplices) {
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var _splices$i = splices[i];
+ var index = _splices$i.index;
+ var removed = _splices$i.removed;
+ var addedCount = _splices$i.addedCount;
+
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ var maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ (function () {
+ var queuedSplices = repeat.__queuedSplices = [];
+
+ var runQueuedSplices = function runQueuedSplices() {
+ if (!queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ var nextPromise = _this2._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ })();
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._runSplices = function _runSplices(repeat, array, splices) {
+ var _this3 = this;
var removeDelta = 0;
- var viewSlot = repeat.viewSlot;
var rmPromises = [];
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var removed = splice.removed;
- var viewIndex = this._getViewIndex(repeat, viewSlot, splice.index);
- if (viewIndex >= 0) {
- for (var j = 0, jj = removed.length; j < jj; ++j) {
- var viewOrPromise = viewSlot.removeAt(viewIndex + removeDelta + rmPromises.length, true);
-
- var _length = viewSlot.children.length;
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, repeat.items[_length], _length, repeat.items.length);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.isAttached = false;
- repeat.viewSlot.add(view);
- repeat.viewSlot.isAttached = true;
-
- if (viewOrPromise instanceof Promise) {
- rmPromises.push(viewOrPromise);
- }
+ for (var j = 0, jj = removed.length; j < jj; ++j) {
+ var viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
}
- removeDelta -= splice.addedCount;
}
+ removeDelta -= splice.addedCount;
}
if (rmPromises.length > 0) {
- Promise.all(rmPromises).then(function () {
- _this._handleAddedSplices(repeat, array, splices);
- _this._updateViews(repeat, array, splices);
+ return Promise.all(rmPromises).then(function () {
+ _this3._handleAddedSplices(repeat, array, splices);
+ (0, _utilities.updateVirtualOverrideContexts)(repeat, 0);
});
- } else {
- this._handleAddedSplices(repeat, array, splices);
- this._updateViews(repeat, array, splices);
}
+ this._handleAddedSplices(repeat, array, splices);
+ (0, _utilities.updateVirtualOverrideContexts)(repeat, 0);
};
- ArrayVirtualRepeatStrategy.prototype._updateViews = function _updateViews(repeat, items, splices) {
- var totalAdded = 0;
- var totalRemoved = 0;
- repeat.items = items;
-
- for (var i = 0, ii = splices.length; i < ii; ++i) {
- var splice = splices[0];
- totalAdded += splice.addedCount;
- totalRemoved += splice.removed.length;
+ ArrayVirtualRepeatStrategy.prototype._removeViewAt = function _removeViewAt(repeat, collectionIndex, returnToCache) {
+ var viewOrPromise = void 0;
+ var view = void 0;
+ var viewSlot = repeat.viewSlot;
+ var viewCount = repeat.viewCount();
+ var viewAddIndex = void 0;
+
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ var collectionAddIndex = void 0;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ var data = repeat.items[collectionAddIndex];
+ if (data) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ (0, _utilities.rebindAndMoveView)(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
}
- var index = repeat._getIndexOfFirstView() - totalRemoved;
-
- if (index < 0) {
- index = 0;
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(function () {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
}
- var viewSlot = repeat.viewSlot;
-
- for (var i = 0, ii = viewSlot.children.length; i < ii; ++i) {
- var view = viewSlot.children[i];
- var nextIndex = index + i;
- var itemsLength = items.length;
- if (nextIndex <= itemsLength - 1) {
- view.bindingContext[repeat.local] = items[nextIndex];
- _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext(view.overrideContext, nextIndex, itemsLength);
- }
- }
+ repeat._adjustBufferHeights();
+ };
- var bufferDelta = repeat.itemHeight * totalAdded + repeat.itemHeight * -totalRemoved;
+ ArrayVirtualRepeatStrategy.prototype._isIndexBeforeViewSlot = function _isIndexBeforeViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ };
- if (repeat._bottomBufferHeight + bufferDelta < 0) {
- repeat._topBufferHeight = repeat._topBufferHeight + bufferDelta;
- } else {
- repeat._bottomBufferHeight = repeat._bottomBufferHeight + bufferDelta;
- }
+ ArrayVirtualRepeatStrategy.prototype._isIndexAfterViewSlot = function _isIndexAfterViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ };
- if (repeat._bottomBufferHeight > 0) {
- repeat.isLastIndex = false;
+ ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
+ if (repeat.viewCount() === 0) {
+ return -1;
}
- repeat._adjustBufferHeights();
+ var topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
};
ArrayVirtualRepeatStrategy.prototype._handleAddedSplices = function _handleAddedSplices(repeat, array, splices) {
- var spliceIndexLow = undefined;
var arrayLength = array.length;
+ var viewSlot = repeat.viewSlot;
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var addIndex = splice.index;
var end = splice.index + splice.addedCount;
-
- if (typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index) {
- spliceIndexLow = addIndex;
- }
-
for (; addIndex < end; ++addIndex) {
- var overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.insert(addIndex, view);
+ var hasDistanceToBottomViewPort = (0, _utilities.getElementDistanceToBottomViewPort)(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || !this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex) || hasDistanceToBottomViewPort) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
}
}
-
- return spliceIndexLow;
- };
-
- ArrayVirtualRepeatStrategy.prototype._isIndexInDom = function _isIndexInDom(viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return false;
- }
-
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var indexHi = viewSlot.children[viewSlot.children.length - 1].overrideContext.$index;
-
- return index >= indexLow && index <= indexHi;
- };
-
- ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return -1;
- }
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var viewIndex = index - indexLow;
- if (viewIndex > repeat._viewsLength - 1) {
- viewIndex = -1;
- }
- return viewIndex;
+ repeat._adjustBufferHeights();
};
return ArrayVirtualRepeatStrategy;
-})(_aureliaTemplatingResourcesArrayRepeatStrategy.ArrayRepeatStrategy);
-
-exports.ArrayVirtualRepeatStrategy = ArrayVirtualRepeatStrategy;
\ No newline at end of file
+}(_arrayRepeatStrategy.ArrayRepeatStrategy);
\ No newline at end of file
diff --git a/dist/commonjs/aurelia-ui-virtualization.d.ts b/dist/commonjs/aurelia-ui-virtualization.d.ts
new file mode 100644
index 0000000..cc50ca3
--- /dev/null
+++ b/dist/commonjs/aurelia-ui-virtualization.d.ts
@@ -0,0 +1,131 @@
+declare module 'aurelia-ui-virtualization' {
+ import {
+ updateOverrideContext,
+ createFullOverrideContext,
+ getItemsSourceExpression,
+ isOneTime,
+ unwrapExpression,
+ updateOneTimeBinding
+ } from 'aurelia-templating-resources/repeat-utilities';
+ import {
+ ArrayRepeatStrategy
+ } from 'aurelia-templating-resources/array-repeat-strategy';
+ import {
+ RepeatStrategyLocator
+ } from 'aurelia-templating-resources/repeat-strategy-locator';
+ import {
+ inject
+ } from 'aurelia-dependency-injection';
+ import {
+ ObserverLocator
+ } from 'aurelia-binding';
+ import {
+ BoundViewFactory,
+ ViewSlot,
+ TargetInstruction,
+ customAttribute,
+ bindable,
+ templateController
+ } from 'aurelia-templating';
+ import {
+ AbstractRepeater
+ } from 'aurelia-templating-resources';
+ import {
+ viewsRequireLifecycle
+ } from 'aurelia-templating-resources/analyze-view-factory';
+ export function calcOuterHeight(element: any): any;
+ export function insertBeforeNode(view: any, bottomBuffer: any): any;
+
+ /**
+ * Update the override context.
+ * @param startIndex index in collection where to start updating.
+ */
+ export function updateVirtualOverrideContexts(repeat: any, startIndex: any): any;
+ export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void;
+ export function getStyleValue(element: any, style: any): any;
+ export function getElementDistanceToBottomViewPort(element: any): any;
+
+ /**
+ * A strategy for repeating a template over an array.
+ */
+ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+
+ // create first item to calculate the heights
+ createFirstItem(repeat: any): any;
+
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat: any, items: any): any;
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat: any, array: any, splices: any): any;
+ }
+ export class ViewStrategyLocator {
+ getStrategy(element: any): any;
+ }
+ export class TableStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class DefaultStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor();
+ }
+ export class VirtualRepeat extends AbstractRepeater {
+ _first: any;
+ _previousFirst: any;
+ _viewsLength: any;
+ _lastRebind: any;
+ _topBufferHeight: any;
+ _bottomBufferHeight: any;
+ _bufferSize: any;
+ _scrollingDown: any;
+ _scrollingUp: any;
+ _switchedDirection: any;
+ _isAttached: any;
+ _ticking: any;
+ _fixedHeightContainer: any;
+ _hasCalculatedSizes: any;
+ _isAtTop: any;
+ items: any;
+ local: any;
+ constructor(element: any, viewFactory: any, instruction: any, viewSlot: any, observerLocator: any, strategyLocator: any, viewStrategyLocator: any);
+ attached(): any;
+ bind(bindingContext: any, overrideContext: any): any;
+ call(context: any, changes: any): any;
+ detached(): any;
+ itemsChanged(): any;
+ unbind(): any;
+ handleCollectionMutated(collection: any, changes: any): any;
+ handleInnerCollectionMutated(collection: any, changes: any): any;
+
+ // @override AbstractRepeater
+ viewCount(): any;
+ views(): any;
+ view(index: any): any;
+ addView(bindingContext: any, overrideContext: any): any;
+ insertView(index: any, bindingContext: any, overrideContext: any): any;
+ removeAllViews(returnToCache: any, skipAnimation: any): any;
+ removeView(index: any, returnToCache: any, skipAnimation: any): any;
+ updateBindings(view: View): any;
+ }
+}
\ No newline at end of file
diff --git a/dist/commonjs/index.js b/dist/commonjs/index.js
index cf41e2a..fae8111 100644
--- a/dist/commonjs/index.js
+++ b/dist/commonjs/index.js
@@ -1,15 +1,15 @@
'use strict';
-exports.__esModule = true;
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtualRepeat = undefined;
exports.configure = configure;
var _virtualRepeat = require('./virtual-repeat');
-var _virtualList = require('./virtual-list');
-
function configure(config) {
- config.globalResources('./virtual-repeat', './virtual-list');
+ config.globalResources('./virtual-repeat');
}
-exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
-exports.VirtualList = _virtualList.VirtualList;
\ No newline at end of file
+exports.VirtualRepeat = _virtualRepeat.VirtualRepeat;
\ No newline at end of file
diff --git a/dist/commonjs/utilities.js b/dist/commonjs/utilities.js
index 660edb7..130ce49 100644
--- a/dist/commonjs/utilities.js
+++ b/dist/commonjs/utilities.js
@@ -1,39 +1,74 @@
'use strict';
-exports.__esModule = true;
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
exports.calcOuterHeight = calcOuterHeight;
-exports.calcScrollHeight = calcScrollHeight;
exports.insertBeforeNode = insertBeforeNode;
+exports.updateVirtualOverrideContexts = updateVirtualOverrideContexts;
+exports.rebindAndMoveView = rebindAndMoveView;
+exports.getStyleValue = getStyleValue;
+exports.getElementDistanceToBottomViewPort = getElementDistanceToBottomViewPort;
+
+var _repeatUtilities = require('aurelia-templating-resources/repeat-utilities');
function calcOuterHeight(element) {
- var height;
+ var height = void 0;
height = element.getBoundingClientRect().height;
height += getStyleValue(element, 'marginTop');
height += getStyleValue(element, 'marginBottom');
return height;
}
-function calcScrollHeight(element) {
- var height;
- height = element.getBoundingClientRect().height;
- height -= getStyleValue(element, 'borderTopWidth');
- height -= getStyleValue(element, 'borderBottomWidth');
- return height;
-}
-
-function insertBeforeNode(view, scrollView, node) {
+function insertBeforeNode(view, bottomBuffer) {
var viewStart = view.firstChild;
var element = viewStart.nextSibling;
var viewEnd = view.lastChild;
+ var parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+}
- scrollView.insertBefore(viewEnd, node);
- scrollView.insertBefore(element, viewEnd);
- scrollView.insertBefore(viewStart, element);
+function updateVirtualOverrideContexts(repeat, startIndex) {
+ var views = repeat.viewSlot.children;
+ var viewLength = views.length;
+ var collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ var delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ (0, _repeatUtilities.updateOverrideContext)(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+}
+
+function rebindAndMoveView(repeat, view, index, moveToBottom) {
+ var items = repeat.items;
+ var viewSlot = repeat.viewSlot;
+ (0, _repeatUtilities.updateOverrideContext)(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
}
function getStyleValue(element, style) {
- var currentStyle, styleValue;
+ var currentStyle = void 0;
+ var styleValue = void 0;
currentStyle = element.currentStyle || window.getComputedStyle(element);
- styleValue = parseInt(currentStyle[style]);
+ styleValue = parseInt(currentStyle[style], 10);
return Number.isNaN(styleValue) ? 0 : styleValue;
+}
+
+function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
}
\ No newline at end of file
diff --git a/dist/commonjs/view-strategy.js b/dist/commonjs/view-strategy.js
index 224dcdb..c0178e7 100644
--- a/dist/commonjs/view-strategy.js
+++ b/dist/commonjs/view-strategy.js
@@ -59,9 +59,9 @@ var TableStrategy = exports.TableStrategy = function () {
return buffer;
};
- TableStrategy.prototype.removeBufferElements = function removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer.parentElement);
- scrollList.removeChild(bottomBuffer.parentElement);
+ TableStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
};
return TableStrategy;
@@ -81,7 +81,9 @@ var DefaultStrategy = exports.DefaultStrategy = function () {
};
DefaultStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
- (0, _utilities.insertBeforeNode)(view, bottomBuffer);
+ var previousSibling = bottomBuffer.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ (0, _utilities.insertBeforeNode)(view, referenceNode);
};
DefaultStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
@@ -101,8 +103,8 @@ var DefaultStrategy = exports.DefaultStrategy = function () {
};
DefaultStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
- element.removeChild(topBuffer);
- element.removeChild(bottomBuffer);
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
};
return DefaultStrategy;
diff --git a/dist/commonjs/virtual-list.html b/dist/commonjs/virtual-list.html
deleted file mode 100644
index fcba809..0000000
--- a/dist/commonjs/virtual-list.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/dist/commonjs/virtual-list.js b/dist/commonjs/virtual-list.js
deleted file mode 100644
index db77dc1..0000000
--- a/dist/commonjs/virtual-list.js
+++ /dev/null
@@ -1,36 +0,0 @@
-'use strict';
-
-exports.__esModule = true;
-
-var _createDecoratedClass = (function () { function defineProperties(target, descriptors, initializers) { for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } if (descriptor.initializer !== undefined) { initializers[key] = descriptor; continue; } } Object.defineProperty(target, key, descriptor); } } return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); return Constructor; }; })();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-function _defineDecoratedPropertyDescriptor(target, key, descriptors) { var _descriptor = descriptors[key]; if (!_descriptor) return; var descriptor = {}; for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; descriptor.value = descriptor.initializer ? descriptor.initializer.call(target) : undefined; Object.defineProperty(target, key, descriptor); }
-
-var _aureliaTemplating = require('aurelia-templating');
-
-var VirtualList = (function () {
- var _instanceInitializers = {};
-
- function VirtualList() {
- _classCallCheck(this, VirtualList);
-
- _defineDecoratedPropertyDescriptor(this, 'items', _instanceInitializers);
- }
-
- VirtualList.prototype.bind = function bind(bindingContext, overrideContext) {
- this.$parent = bindingContext;
- };
-
- _createDecoratedClass(VirtualList, [{
- key: 'items',
- decorators: [_aureliaTemplating.bindable],
- initializer: null,
- enumerable: true
- }], null, _instanceInitializers);
-
- return VirtualList;
-})();
-
-exports.VirtualList = VirtualList;
\ No newline at end of file
diff --git a/dist/commonjs/virtual-repeat-strategy-locator.js b/dist/commonjs/virtual-repeat-strategy-locator.js
index 8be9fa3..1d471c6 100644
--- a/dist/commonjs/virtual-repeat-strategy-locator.js
+++ b/dist/commonjs/virtual-repeat-strategy-locator.js
@@ -1,31 +1,36 @@
'use strict';
-exports.__esModule = true;
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtualRepeatStrategyLocator = undefined;
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _repeatStrategyLocator = require('aurelia-templating-resources/repeat-strategy-locator');
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _arrayVirtualRepeatStrategy = require('./array-virtual-repeat-strategy');
-var _aureliaTemplatingResourcesRepeatStrategyLocator = require('aurelia-templating-resources/repeat-strategy-locator');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-var _arrayVirtualRepeatStrategy = require('./array-virtual-repeat-strategy');
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-var VirtualRepeatStrategyLocator = (function (_RepeatStrategyLocator) {
- _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocator);
+var VirtualRepeatStrategyLocator = exports.VirtualRepeatStrategyLocator = function (_RepeatStrategyLocato) {
+ _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocato);
function VirtualRepeatStrategyLocator() {
_classCallCheck(this, VirtualRepeatStrategyLocator);
- _RepeatStrategyLocator.call(this);
- this.matchers = [];
- this.strategies = [];
+ var _this = _possibleConstructorReturn(this, _RepeatStrategyLocato.call(this));
- this.addStrategy(function (items) {
+ _this.matchers = [];
+ _this.strategies = [];
+
+ _this.addStrategy(function (items) {
return items instanceof Array;
}, new _arrayVirtualRepeatStrategy.ArrayVirtualRepeatStrategy());
+ return _this;
}
return VirtualRepeatStrategyLocator;
-})(_aureliaTemplatingResourcesRepeatStrategyLocator.RepeatStrategyLocator);
-
-exports.VirtualRepeatStrategyLocator = VirtualRepeatStrategyLocator;
\ No newline at end of file
+}(_repeatStrategyLocator.RepeatStrategyLocator);
\ No newline at end of file
diff --git a/dist/commonjs/virtual-repeat.js b/dist/commonjs/virtual-repeat.js
index dc7c40d..3ebdf9e 100644
--- a/dist/commonjs/virtual-repeat.js
+++ b/dist/commonjs/virtual-repeat.js
@@ -1,12 +1,11 @@
'use strict';
-exports.__esModule = true;
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtualRepeat = undefined;
-var _createDecoratedClass = (function () { function defineProperties(target, descriptors, initializers) { for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } if (descriptor.initializer !== undefined) { initializers[key] = descriptor; continue; } } Object.defineProperty(target, key, descriptor); } } return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); return Constructor; }; })();
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-function _defineDecoratedPropertyDescriptor(target, key, descriptors) { var _descriptor = descriptors[key]; if (!_descriptor) return; var descriptor = {}; for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; descriptor.value = descriptor.initializer ? descriptor.initializer.call(target) : undefined; Object.defineProperty(target, key, descriptor); }
+var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
var _aureliaDependencyInjection = require('aurelia-dependency-injection');
@@ -14,9 +13,11 @@ var _aureliaBinding = require('aurelia-binding');
var _aureliaTemplating = require('aurelia-templating');
-var _aureliaTemplatingResourcesRepeatUtilities = require('aurelia-templating-resources/repeat-utilities');
+var _aureliaTemplatingResources = require('aurelia-templating-resources');
+
+var _repeatUtilities = require('aurelia-templating-resources/repeat-utilities');
-var _aureliaTemplatingResourcesAnalyzeViewFactory = require('aurelia-templating-resources/analyze-view-factory');
+var _analyzeViewFactory = require('aurelia-templating-resources/analyze-view-factory');
var _utilities = require('./utilities');
@@ -24,80 +25,123 @@ var _virtualRepeatStrategyLocator = require('./virtual-repeat-strategy-locator')
var _viewStrategy = require('./view-strategy');
-var VirtualRepeat = (function () {
- var _instanceInitializers = {};
-
- _createDecoratedClass(VirtualRepeat, [{
- key: 'items',
- decorators: [_aureliaTemplating.bindable],
- initializer: null,
- enumerable: true
- }, {
- key: 'local',
- decorators: [_aureliaTemplating.bindable],
- initializer: null,
- enumerable: true
- }], null, _instanceInitializers);
+function _initDefineProp(target, property, descriptor, context) {
+ if (!descriptor) return;
+ Object.defineProperty(target, property, {
+ enumerable: descriptor.enumerable,
+ configurable: descriptor.configurable,
+ writable: descriptor.writable,
+ value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
+ });
+}
- function VirtualRepeat(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
- _classCallCheck(this, _VirtualRepeat);
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- this._first = 0;
- this._previousFirst = 0;
- this._viewsLength = 0;
- this._lastRebind = 0;
- this._topBufferHeight = 0;
- this._bottomBufferHeight = 0;
- this._bufferSize = 5;
- this._scrollingDown = false;
- this._scrollingUp = false;
- this._switchedDirection = false;
- this._isAttached = false;
- this._ticking = false;
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
+ var desc = {};
+ Object['ke' + 'ys'](descriptor).forEach(function (key) {
+ desc[key] = descriptor[key];
+ });
+ desc.enumerable = !!desc.enumerable;
+ desc.configurable = !!desc.configurable;
+
+ if ('value' in desc || desc.initializer) {
+ desc.writable = true;
+ }
+
+ desc = decorators.slice().reverse().reduce(function (desc, decorator) {
+ return decorator(target, property, desc) || desc;
+ }, desc);
+
+ if (context && desc.initializer !== void 0) {
+ desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
+ desc.initializer = undefined;
+ }
- _defineDecoratedPropertyDescriptor(this, 'items', _instanceInitializers);
-
- _defineDecoratedPropertyDescriptor(this, 'local', _instanceInitializers);
-
- this.element = element;
- this.viewFactory = viewFactory;
- this.instruction = instruction;
- this.viewSlot = viewSlot;
- this.observerLocator = observerLocator;
- this.strategyLocator = strategyLocator;
- this.viewStrategyLocator = viewStrategyLocator;
- this.local = 'item';
- this.sourceExpression = _aureliaTemplatingResourcesRepeatUtilities.getItemsSourceExpression(this.instruction, 'virtual-repeat.for');
- this.isOneTime = _aureliaTemplatingResourcesRepeatUtilities.isOneTime(this.sourceExpression);
- this.viewsRequireLifecycle = _aureliaTemplatingResourcesAnalyzeViewFactory.viewsRequireLifecycle(viewFactory);
+ if (desc.initializer === void 0) {
+ Object['define' + 'Property'](target, property, desc);
+ desc = null;
+ }
+
+ return desc;
+}
+
+function _initializerWarningHelper(descriptor, context) {
+ throw new Error('Decorating class property failed. Please ensure that transform-class-properties is enabled.');
+}
+
+var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec2 = (0, _aureliaDependencyInjection.inject)(Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaBinding.ObserverLocator, _virtualRepeatStrategyLocator.VirtualRepeatStrategyLocator, _viewStrategy.ViewStrategyLocator), _dec(_class = (0, _aureliaTemplating.templateController)(_class = _dec2(_class = (_class2 = function (_AbstractRepeater) {
+ _inherits(VirtualRepeat, _AbstractRepeater);
+
+ function VirtualRepeat(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
+ _classCallCheck(this, VirtualRepeat);
+
+ var _this = _possibleConstructorReturn(this, _AbstractRepeater.call(this, {
+ local: 'item',
+ viewsRequireLifecycle: (0, _analyzeViewFactory.viewsRequireLifecycle)(viewFactory)
+ }));
+
+ _this._first = 0;
+ _this._previousFirst = 0;
+ _this._viewsLength = 0;
+ _this._lastRebind = 0;
+ _this._topBufferHeight = 0;
+ _this._bottomBufferHeight = 0;
+ _this._bufferSize = 5;
+ _this._scrollingDown = false;
+ _this._scrollingUp = false;
+ _this._switchedDirection = false;
+ _this._isAttached = false;
+ _this._ticking = false;
+ _this._fixedHeightContainer = false;
+ _this._hasCalculatedSizes = false;
+ _this._isAtTop = true;
+
+ _initDefineProp(_this, 'items', _descriptor, _this);
+
+ _initDefineProp(_this, 'local', _descriptor2, _this);
+
+ _this.element = element;
+ _this.viewFactory = viewFactory;
+ _this.instruction = instruction;
+ _this.viewSlot = viewSlot;
+ _this.observerLocator = observerLocator;
+ _this.strategyLocator = strategyLocator;
+ _this.viewStrategyLocator = viewStrategyLocator;
+ _this.sourceExpression = (0, _repeatUtilities.getItemsSourceExpression)(_this.instruction, 'virtual-repeat.for');
+ _this.isOneTime = (0, _repeatUtilities.isOneTime)(_this.sourceExpression);
+ return _this;
}
VirtualRepeat.prototype.attached = function attached() {
- var _this = this;
+ var _this2 = this;
this._isAttached = true;
var element = this.element;
this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
- this.scrollList = this.viewStrategy.getScrollList(element);
this.scrollContainer = this.viewStrategy.getScrollContainer(element);
- this.topBuffer = this.viewStrategy.createTopBufferElement(this.scrollList, element);
- this.bottomBuffer = this.viewStrategy.createBottomBufferElement(this.scrollList, element);
+ this.topBuffer = this.viewStrategy.createTopBufferElement(element);
+ this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
this.itemsChanged();
this.scrollListener = function () {
- return _this._onScroll();
+ return _this2._onScroll();
};
- this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ var containerStyle = this.scrollContainer.style;
+ if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
+ this._fixedHeightContainer = true;
+ this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ } else {
+ document.addEventListener('scroll', this.scrollListener);
+ }
};
VirtualRepeat.prototype.bind = function bind(bindingContext, overrideContext) {
- var _this2 = this;
-
this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
this._itemsLength = this.items.length;
-
- window.onresize = function () {
- _this2._handleResize();
- };
};
VirtualRepeat.prototype.call = function call(context, changes) {
@@ -117,12 +161,12 @@ var VirtualRepeat = (function () {
this._switchedDirection = false;
this._isAttached = false;
this._ticking = false;
- this.viewStrategy.removeBufferElements(this.scrollList, this.topBuffer, this.bottomBuffer);
+ this._hasCalculatedSizes = false;
+ this.viewStrategy.removeBufferElements(this.element, this.topBuffer, this.bottomBuffer);
this.isLastIndex = false;
- this.scrollList = null;
this.scrollContainer = null;
this.scrollContainerHeight = null;
- this.viewSlot.removeAll(true);
+ this.removeAllViews(true);
if (this.scrollHandler) {
this.scrollHandler.dispose();
}
@@ -137,8 +181,10 @@ var VirtualRepeat = (function () {
}
var items = this.items;
this.strategy = this.strategyLocator.getStrategy(items);
- this.strategy.createFirstItem(this);
- this._calcInitialHeights();
+ if (items.length > 0) {
+ this.strategy.createFirstItem(this);
+ }
+ this._calcInitialHeights(items.length);
if (!this.isOneTime && !this._observeInnerCollection()) {
this._observeCollection();
}
@@ -153,6 +199,7 @@ var VirtualRepeat = (function () {
};
VirtualRepeat.prototype.handleCollectionMutated = function handleCollectionMutated(collection, changes) {
+ this._handlingMutations = true;
this._itemsLength = collection.length;
this.strategy.instanceMutated(this, collection, changes);
};
@@ -179,12 +226,16 @@ var VirtualRepeat = (function () {
VirtualRepeat.prototype._onScroll = function _onScroll() {
var _this4 = this;
- if (!this._ticking) {
+ if (!this._ticking && !this._handlingMutations) {
requestAnimationFrame(function () {
return _this4._handleScroll();
});
this._ticking = true;
}
+
+ if (this._handlingMutations) {
+ this._handlingMutations = false;
+ }
};
VirtualRepeat.prototype._handleScroll = function _handleScroll() {
@@ -192,73 +243,55 @@ var VirtualRepeat = (function () {
return;
}
var itemHeight = this.itemHeight;
- var scrollTop = this.scrollContainer.scrollTop;
+ var scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
this._first = Math.floor(scrollTop / itemHeight);
+ this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
this._checkScrolling();
- if (this._scrollingDown && (this._hasScrolledDownTheBuffer() || this._switchedDirection && this._hasScrolledDownTheBufferFromTop())) {
+ if (this._scrollingDown) {
var viewsToMove = this._first - this._lastRebind;
if (this._switchedDirection) {
- viewsToMove = this.isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
}
- this.isAtTop = false;
+ this._isAtTop = false;
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
- var test = 0;
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
if (this._bottomBufferHeight >= 0) {
this._adjustBufferHeights();
}
- } else if (this._scrollingUp && (this._hasScrolledUpTheBuffer() || this._switchedDirection && this._hasScrolledUpTheBufferFromBottom())) {
- var viewsToMove = this._lastRebind - this._first;
- if (this._switchedDirection) {
- if (this.isLastIndex) {
- viewsToMove = this.items.length - this._first - this.elementsInView;
- } else {
- viewsToMove = this._bufferSize - (this._first - this._lastRebind);
- }
- }
- this.isLastIndex = false;
- this._lastRebind = this._first;
- var movedViewsCount = this._moveViews(viewsToMove);
- this.movedViewsCount = movedViewsCount;
- var adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
- this._switchedDirection = false;
- this._topBufferHeight = this._topBufferHeight - adjustHeight;
- this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
- if (this._topBufferHeight >= 0) {
- this._adjustBufferHeights();
+ } else if (this._scrollingUp) {
+ var _viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ _viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ _viewsToMove = this._bufferSize - (this._first - this._lastRebind);
}
}
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ var _movedViewsCount = this._moveViews(_viewsToMove);
+ this.movedViewsCount = _movedViewsCount;
+ var _adjustHeight = _movedViewsCount < _viewsToMove ? this._topBufferHeight : itemHeight * _movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - _adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + _adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
this._previousFirst = this._first;
this._ticking = false;
};
- VirtualRepeat.prototype._handleResize = function _handleResize() {
- var children = this.viewSlot.children,
- childrenLength = children.length,
- overrideContext,
- view,
- addIndex;
-
- this.scrollContainerHeight = _utilities.calcScrollHeight(this.scrollContainer);
- this._viewsLength = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
-
- if (this._viewsLength > childrenLength) {
- addIndex = children[childrenLength - 1].overrideContext.$index + 1;
- overrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext(this, this.items[addIndex], addIndex, this.items.length);
- view = this.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- this.viewSlot.insert(childrenLength, view);
- } else if (this._viewsLength < childrenLength) {
- this._viewsLength = childrenLength;
- }
- };
-
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -269,7 +302,7 @@ var VirtualRepeat = (function () {
this._switchedDirection = false;
}
this._isScrolling = true;
- } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this.isAtTop)) {
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
if (!this._scrollingUp) {
this._scrollingDown = false;
this._scrollingUp = true;
@@ -283,27 +316,9 @@ var VirtualRepeat = (function () {
}
};
- VirtualRepeat.prototype._hasScrolledDownTheBuffer = function _hasScrolledDownTheBuffer() {
- var atBottom = this._first + this._viewsLength >= this.items.length;
- var itemsAddedWhileAtBottom = atBottom && this._first > this._lastRebind;
- return this._first - this._lastRebind >= this._bufferSize || itemsAddedWhileAtBottom;
- };
-
- VirtualRepeat.prototype._hasScrolledDownTheBufferFromTop = function _hasScrolledDownTheBufferFromTop() {
- return this._first - this._bufferSize > 0;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBuffer = function _hasScrolledUpTheBuffer() {
- return this._lastRebind - this._first >= this._bufferSize;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBufferFromBottom = function _hasScrolledUpTheBufferFromBottom() {
- return this._first + this._bufferSize < this.items.length;
- };
-
VirtualRepeat.prototype._adjustBufferHeights = function _adjustBufferHeights() {
this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
- this.bottomBuffer.setAttribute("style", 'height: ' + this._bottomBufferHeight + 'px');
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
};
VirtualRepeat.prototype._unsubscribeCollection = function _unsubscribeCollection() {
@@ -323,63 +338,69 @@ var VirtualRepeat = (function () {
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5.isAtTop;
+ return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
};
- var viewSlot = this.viewSlot;
- var childrenLength = viewSlot.children.length;
+ var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
var items = this.items;
- var scrollList = this.scrollList;
var index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
var i = 0;
while (i < length && !isAtFirstOrLastIndex()) {
- var view = viewSlot.children[viewIndex];
+ var view = this.view(viewIndex);
var nextIndex = getNextIndex(index, i);
- _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext(view.overrideContext, nextIndex, items.length);
- view.bindingContext[this.local] = items[nextIndex];
- if (this._scrollingDown) {
- viewSlot.children.push(viewSlot.children.shift());
- this.viewStrategy.moveViewLast(view, scrollList, childrenLength);
- this.isLastIndex = nextIndex >= items.length - 1;
- } else {
- viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
- this.viewStrategy.moveViewFirst(view, scrollList);
- this.isAtTop = nextIndex <= 0;
+ this.isLastIndex = nextIndex >= items.length - 1;
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
+ (0, _utilities.rebindAndMoveView)(this, view, nextIndex, this._scrollingDown);
+ i++;
}
- i++;
}
+
return length - (length - i);
};
VirtualRepeat.prototype._getIndexOfLastView = function _getIndexOfLastView() {
- var children = this.viewSlot.children;
- return children[children.length - 1].overrideContext.$index;
+ return this.view(this.viewCount() - 1).overrideContext.$index;
};
VirtualRepeat.prototype._getIndexOfFirstView = function _getIndexOfFirstView() {
- var children = this.viewSlot.children;
- return children[0].overrideContext.$index;
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
};
- VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights() {
- if (this._viewsLength > 0 && this._itemsLength == this.items.length) {
+ VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights(itemsLength) {
+ if (this._viewsLength > 0 && this._itemsLength === itemsLength || itemsLength <= 0) {
return;
}
- this._itemsLength = this.items.length;
- var listItems = this.scrollList.children;
- this.itemHeight = _utilities.calcOuterHeight(listItems[1]);
- this.scrollContainerHeight = _utilities.calcScrollHeight(this.scrollContainer);
+ this._hasCalculatedSizes = true;
+ this._itemsLength = itemsLength;
+ var firstViewElement = this.view(0).firstChild.nextElementSibling;
+ this.itemHeight = (0, _utilities.calcOuterHeight)(firstViewElement);
+ if (this.itemHeight <= 0) {
+ throw new Error('Could not calculate item height');
+ }
+ this.scrollContainerHeight = this._fixedHeightContainer ? this._calcScrollHeight(this.scrollContainer) : document.documentElement.clientHeight;
this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
this._viewsLength = this.elementsInView * 2 + this._bufferSize;
- this._bottomBufferHeight = this.itemHeight * this.items.length - this.itemHeight * this._viewsLength;
- this.bottomBuffer.setAttribute("style", 'height: ' + this._bottomBufferHeight + 'px');
+ this._bottomBufferHeight = this.itemHeight * itemsLength - this.itemHeight * this._viewsLength;
+ if (this._bottomBufferHeight < 0) {
+ this._bottomBufferHeight = 0;
+ }
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
this._topBufferHeight = 0;
- this.topBuffer.setAttribute("style", 'height: ' + this._topBufferHeight + 'px');
+ this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
this.scrollContainer.scrollTop = 0;
this._first = 0;
};
+ VirtualRepeat.prototype._calcScrollHeight = function _calcScrollHeight(element) {
+ var height = void 0;
+ height = element.getBoundingClientRect().height;
+ height -= (0, _utilities.getStyleValue)(element, 'borderTopWidth');
+ height -= (0, _utilities.getStyleValue)(element, 'borderBottomWidth');
+ return height;
+ };
+
VirtualRepeat.prototype._observeInnerCollection = function _observeInnerCollection() {
var items = this._getInnerCollection();
var strategy = this.strategyLocator.getStrategy(items);
@@ -396,7 +417,7 @@ var VirtualRepeat = (function () {
};
VirtualRepeat.prototype._getInnerCollection = function _getInnerCollection() {
- var expression = _aureliaTemplatingResourcesRepeatUtilities.unwrapExpression(this.sourceExpression);
+ var expression = (0, _repeatUtilities.unwrapExpression)(this.sourceExpression);
if (!expression) {
return null;
}
@@ -412,11 +433,58 @@ var VirtualRepeat = (function () {
}
};
- var _VirtualRepeat = VirtualRepeat;
- VirtualRepeat = _aureliaDependencyInjection.inject(Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaBinding.ObserverLocator, _virtualRepeatStrategyLocator.VirtualRepeatStrategyLocator, _viewStrategy.ViewStrategyLocator)(VirtualRepeat) || VirtualRepeat;
- VirtualRepeat = _aureliaTemplating.templateController(VirtualRepeat) || VirtualRepeat;
- VirtualRepeat = _aureliaTemplating.customAttribute('virtual-repeat')(VirtualRepeat) || VirtualRepeat;
- return VirtualRepeat;
-})();
+ VirtualRepeat.prototype.viewCount = function viewCount() {
+ return this.viewSlot.children.length;
+ };
+
+ VirtualRepeat.prototype.views = function views() {
+ return this.viewSlot.children;
+ };
+
+ VirtualRepeat.prototype.view = function view(index) {
+ return this.viewSlot.children[index];
+ };
+
+ VirtualRepeat.prototype.addView = function addView(bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ };
+
+ VirtualRepeat.prototype.insertView = function insertView(index, bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ };
-exports.VirtualRepeat = VirtualRepeat;
\ No newline at end of file
+ VirtualRepeat.prototype.removeAllViews = function removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.removeView = function removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.updateBindings = function updateBindings(view) {
+ var j = view.bindings.length;
+ while (j--) {
+ (0, _repeatUtilities.updateOneTimeBinding)(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ var k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ var binding = view.controllers[j].boundProperties[k].binding;
+ (0, _repeatUtilities.updateOneTimeBinding)(binding);
+ }
+ }
+ };
+
+ return VirtualRepeat;
+}(_aureliaTemplatingResources.AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [_aureliaTemplating.bindable], {
+ enumerable: true,
+ initializer: null
+}), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, 'local', [_aureliaTemplating.bindable], {
+ enumerable: true,
+ initializer: null
+})), _class2)) || _class) || _class) || _class);
\ No newline at end of file
diff --git a/dist/es2015/array-virtual-repeat-strategy.js b/dist/es2015/array-virtual-repeat-strategy.js
new file mode 100644
index 0000000..a1448e2
--- /dev/null
+++ b/dist/es2015/array-virtual-repeat-strategy.js
@@ -0,0 +1,222 @@
+import { ArrayRepeatStrategy } from 'aurelia-templating-resources/array-repeat-strategy';
+import { createFullOverrideContext } from 'aurelia-templating-resources/repeat-utilities';
+import { updateVirtualOverrideContexts, rebindAndMoveView, getElementDistanceToBottomViewPort } from './utilities';
+
+export let ArrayVirtualRepeatStrategy = class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+ createFirstItem(repeat) {
+ let overrideContext = createFullOverrideContext(repeat, repeat.items[0], 0, 1);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+
+ instanceChanged(repeat, items) {
+ this._inPlaceProcessItems(repeat, items);
+ }
+
+ _standardProcessInstanceChanged(repeat, items) {
+ for (let i = 1, ii = repeat._viewsLength; i < ii; ++i) {
+ let overrideContext = createFullOverrideContext(repeat, items[i], i, ii);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ }
+
+ _inPlaceProcessItems(repeat, items) {
+ let itemsLength = items.length;
+ let viewsLength = repeat.viewCount();
+ let first = repeat._getIndexOfFirstView();
+
+ while (viewsLength > repeat._viewsLength) {
+ viewsLength--;
+ repeat.removeView(viewsLength, true);
+ }
+
+ let local = repeat.local;
+
+ for (let i = 0; i < viewsLength; i++) {
+ let view = repeat.view(i);
+ let last = i === itemsLength - 1;
+ let middle = i !== 0 && !last;
+
+ if (view.bindingContext[local] === items[i + first] && view.overrideContext.$middle === middle && view.overrideContext.$last === last) {
+ continue;
+ }
+
+ view.bindingContext[local] = items[i + first];
+ view.overrideContext.$middle = middle;
+ view.overrideContext.$last = last;
+ repeat.updateBindings(view);
+ }
+
+ let minLength = Math.min(repeat._viewsLength, items.length);
+ for (let i = viewsLength; i < minLength; i++) {
+ let overrideContext = createFullOverrideContext(repeat, items[i], i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ }
+
+ instanceMutated(repeat, array, splices) {
+ this._standardProcessInstanceMutated(repeat, array, splices);
+ }
+
+ _standardProcessInstanceMutated(repeat, array, splices) {
+ if (repeat.__queuedSplices) {
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let { index, removed, addedCount } = splices[i];
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ let maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ let queuedSplices = repeat.__queuedSplices = [];
+
+ let runQueuedSplices = () => {
+ if (!queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ let nextPromise = this._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ }
+ }
+
+ _runSplices(repeat, array, splices) {
+ let removeDelta = 0;
+ let rmPromises = [];
+
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let splice = splices[i];
+ let removed = splice.removed;
+ for (let j = 0, jj = removed.length; j < jj; ++j) {
+ let viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
+ }
+ }
+ removeDelta -= splice.addedCount;
+ }
+
+ if (rmPromises.length > 0) {
+ return Promise.all(rmPromises).then(() => {
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ });
+ }
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ }
+
+ _removeViewAt(repeat, collectionIndex, returnToCache) {
+ let viewOrPromise;
+ let view;
+ let viewSlot = repeat.viewSlot;
+ let viewCount = repeat.viewCount();
+ let viewAddIndex;
+
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ let collectionAddIndex;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ let data = repeat.items[collectionAddIndex];
+ if (data) {
+ let overrideContext = createFullOverrideContext(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ rebindAndMoveView(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ }
+
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(() => {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ }
+
+ repeat._adjustBufferHeights();
+ }
+
+ _isIndexBeforeViewSlot(repeat, viewSlot, index) {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ }
+
+ _isIndexAfterViewSlot(repeat, viewSlot, index) {
+ let viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ }
+
+ _getViewIndex(repeat, viewSlot, index) {
+ if (repeat.viewCount() === 0) {
+ return -1;
+ }
+
+ let topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
+ }
+
+ _handleAddedSplices(repeat, array, splices) {
+ let arrayLength = array.length;
+ let viewSlot = repeat.viewSlot;
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
+ let splice = splices[i];
+ let addIndex = splice.index;
+ let end = splice.index + splice.addedCount;
+ for (; addIndex < end; ++addIndex) {
+ let hasDistanceToBottomViewPort = getElementDistanceToBottomViewPort(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || !this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex) || hasDistanceToBottomViewPort) {
+ let overrideContext = createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
+ }
+ }
+ repeat._adjustBufferHeights();
+ }
+};
\ No newline at end of file
diff --git a/dist/es2015/aurelia-ui-virtualization.d.ts b/dist/es2015/aurelia-ui-virtualization.d.ts
new file mode 100644
index 0000000..cc50ca3
--- /dev/null
+++ b/dist/es2015/aurelia-ui-virtualization.d.ts
@@ -0,0 +1,131 @@
+declare module 'aurelia-ui-virtualization' {
+ import {
+ updateOverrideContext,
+ createFullOverrideContext,
+ getItemsSourceExpression,
+ isOneTime,
+ unwrapExpression,
+ updateOneTimeBinding
+ } from 'aurelia-templating-resources/repeat-utilities';
+ import {
+ ArrayRepeatStrategy
+ } from 'aurelia-templating-resources/array-repeat-strategy';
+ import {
+ RepeatStrategyLocator
+ } from 'aurelia-templating-resources/repeat-strategy-locator';
+ import {
+ inject
+ } from 'aurelia-dependency-injection';
+ import {
+ ObserverLocator
+ } from 'aurelia-binding';
+ import {
+ BoundViewFactory,
+ ViewSlot,
+ TargetInstruction,
+ customAttribute,
+ bindable,
+ templateController
+ } from 'aurelia-templating';
+ import {
+ AbstractRepeater
+ } from 'aurelia-templating-resources';
+ import {
+ viewsRequireLifecycle
+ } from 'aurelia-templating-resources/analyze-view-factory';
+ export function calcOuterHeight(element: any): any;
+ export function insertBeforeNode(view: any, bottomBuffer: any): any;
+
+ /**
+ * Update the override context.
+ * @param startIndex index in collection where to start updating.
+ */
+ export function updateVirtualOverrideContexts(repeat: any, startIndex: any): any;
+ export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void;
+ export function getStyleValue(element: any, style: any): any;
+ export function getElementDistanceToBottomViewPort(element: any): any;
+
+ /**
+ * A strategy for repeating a template over an array.
+ */
+ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+
+ // create first item to calculate the heights
+ createFirstItem(repeat: any): any;
+
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat: any, items: any): any;
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat: any, array: any, splices: any): any;
+ }
+ export class ViewStrategyLocator {
+ getStrategy(element: any): any;
+ }
+ export class TableStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class DefaultStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor();
+ }
+ export class VirtualRepeat extends AbstractRepeater {
+ _first: any;
+ _previousFirst: any;
+ _viewsLength: any;
+ _lastRebind: any;
+ _topBufferHeight: any;
+ _bottomBufferHeight: any;
+ _bufferSize: any;
+ _scrollingDown: any;
+ _scrollingUp: any;
+ _switchedDirection: any;
+ _isAttached: any;
+ _ticking: any;
+ _fixedHeightContainer: any;
+ _hasCalculatedSizes: any;
+ _isAtTop: any;
+ items: any;
+ local: any;
+ constructor(element: any, viewFactory: any, instruction: any, viewSlot: any, observerLocator: any, strategyLocator: any, viewStrategyLocator: any);
+ attached(): any;
+ bind(bindingContext: any, overrideContext: any): any;
+ call(context: any, changes: any): any;
+ detached(): any;
+ itemsChanged(): any;
+ unbind(): any;
+ handleCollectionMutated(collection: any, changes: any): any;
+ handleInnerCollectionMutated(collection: any, changes: any): any;
+
+ // @override AbstractRepeater
+ viewCount(): any;
+ views(): any;
+ view(index: any): any;
+ addView(bindingContext: any, overrideContext: any): any;
+ insertView(index: any, bindingContext: any, overrideContext: any): any;
+ removeAllViews(returnToCache: any, skipAnimation: any): any;
+ removeView(index: any, returnToCache: any, skipAnimation: any): any;
+ updateBindings(view: View): any;
+ }
+}
\ No newline at end of file
diff --git a/dist/es2015/index.js b/dist/es2015/index.js
new file mode 100644
index 0000000..91b4a83
--- /dev/null
+++ b/dist/es2015/index.js
@@ -0,0 +1,7 @@
+import { VirtualRepeat } from './virtual-repeat';
+
+export function configure(config) {
+ config.globalResources('./virtual-repeat');
+}
+
+export { VirtualRepeat };
\ No newline at end of file
diff --git a/dist/es2015/utilities.js b/dist/es2015/utilities.js
new file mode 100644
index 0000000..c124066
--- /dev/null
+++ b/dist/es2015/utilities.js
@@ -0,0 +1,62 @@
+import { updateOverrideContext } from 'aurelia-templating-resources/repeat-utilities';
+
+export function calcOuterHeight(element) {
+ let height;
+ height = element.getBoundingClientRect().height;
+ height += getStyleValue(element, 'marginTop');
+ height += getStyleValue(element, 'marginBottom');
+ return height;
+}
+
+export function insertBeforeNode(view, bottomBuffer) {
+ let viewStart = view.firstChild;
+ let element = viewStart.nextSibling;
+ let viewEnd = view.lastChild;
+ let parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+}
+
+export function updateVirtualOverrideContexts(repeat, startIndex) {
+ let views = repeat.viewSlot.children;
+ let viewLength = views.length;
+ let collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ let delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ updateOverrideContext(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+}
+
+export function rebindAndMoveView(repeat, view, index, moveToBottom) {
+ let items = repeat.items;
+ let viewSlot = repeat.viewSlot;
+ updateOverrideContext(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
+}
+
+export function getStyleValue(element, style) {
+ let currentStyle;
+ let styleValue;
+ currentStyle = element.currentStyle || window.getComputedStyle(element);
+ styleValue = parseInt(currentStyle[style], 10);
+ return Number.isNaN(styleValue) ? 0 : styleValue;
+}
+
+export function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
+}
\ No newline at end of file
diff --git a/dist/es2015/view-strategy.js b/dist/es2015/view-strategy.js
new file mode 100644
index 0000000..2df3c5f
--- /dev/null
+++ b/dist/es2015/view-strategy.js
@@ -0,0 +1,84 @@
+import { insertBeforeNode } from './utilities';
+
+export let ViewStrategyLocator = class ViewStrategyLocator {
+ getStrategy(element) {
+ if (element.parentNode.localName === 'tbody') {
+ return new TableStrategy();
+ }
+ return new DefaultStrategy();
+ }
+};
+
+export let TableStrategy = class TableStrategy {
+ getScrollContainer(element) {
+ return element.parentNode;
+ }
+
+ moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.parentElement.nextElementSibling.previousSibling);
+ }
+
+ moveViewLast(view, bottomBuffer) {
+ insertBeforeNode(view, bottomBuffer.parentElement);
+ }
+
+ createTopBufferElement(element) {
+ let tr = document.createElement('tr');
+ let buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentElement.insertBefore(tr, element);
+ return buffer;
+ }
+
+ createBottomBufferElement(element) {
+ let tr = document.createElement('tr');
+ let buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentNode.insertBefore(tr, element.nextSibling);
+ return buffer;
+ }
+
+ removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
+ }
+};
+
+export let DefaultStrategy = class DefaultStrategy {
+ getScrollContainer(element) {
+ return element.parentNode;
+ }
+
+ moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.nextElementSibling.previousSibling);
+ }
+
+ moveViewLast(view, bottomBuffer) {
+ let previousSibling = bottomBuffer.previousSibling;
+ let referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ insertBeforeNode(view, referenceNode);
+ }
+
+ createTopBufferElement(element) {
+ let elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ let buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentElement.insertBefore(buffer, element);
+ return buffer;
+ }
+
+ createBottomBufferElement(element) {
+ let elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ let buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentNode.insertBefore(buffer, element.nextSibling);
+ return buffer;
+ }
+
+ removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
+ }
+};
\ No newline at end of file
diff --git a/dist/es2015/virtual-repeat-strategy-locator.js b/dist/es2015/virtual-repeat-strategy-locator.js
new file mode 100644
index 0000000..7b08a88
--- /dev/null
+++ b/dist/es2015/virtual-repeat-strategy-locator.js
@@ -0,0 +1,12 @@
+import { RepeatStrategyLocator } from 'aurelia-templating-resources/repeat-strategy-locator';
+import { ArrayVirtualRepeatStrategy } from './array-virtual-repeat-strategy';
+
+export let VirtualRepeatStrategyLocator = class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor() {
+ super();
+ this.matchers = [];
+ this.strategies = [];
+
+ this.addStrategy(items => items instanceof Array, new ArrayVirtualRepeatStrategy());
+ }
+};
\ No newline at end of file
diff --git a/dist/es2015/virtual-repeat.js b/dist/es2015/virtual-repeat.js
new file mode 100644
index 0000000..371b21e
--- /dev/null
+++ b/dist/es2015/virtual-repeat.js
@@ -0,0 +1,440 @@
+var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
+
+function _initDefineProp(target, property, descriptor, context) {
+ if (!descriptor) return;
+ Object.defineProperty(target, property, {
+ enumerable: descriptor.enumerable,
+ configurable: descriptor.configurable,
+ writable: descriptor.writable,
+ value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
+ });
+}
+
+function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
+ var desc = {};
+ Object['ke' + 'ys'](descriptor).forEach(function (key) {
+ desc[key] = descriptor[key];
+ });
+ desc.enumerable = !!desc.enumerable;
+ desc.configurable = !!desc.configurable;
+
+ if ('value' in desc || desc.initializer) {
+ desc.writable = true;
+ }
+
+ desc = decorators.slice().reverse().reduce(function (desc, decorator) {
+ return decorator(target, property, desc) || desc;
+ }, desc);
+
+ if (context && desc.initializer !== void 0) {
+ desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
+ desc.initializer = undefined;
+ }
+
+ if (desc.initializer === void 0) {
+ Object['define' + 'Property'](target, property, desc);
+ desc = null;
+ }
+
+ return desc;
+}
+
+function _initializerWarningHelper(descriptor, context) {
+ throw new Error('Decorating class property failed. Please ensure that transform-class-properties is enabled.');
+}
+
+import { inject } from 'aurelia-dependency-injection';
+import { ObserverLocator } from 'aurelia-binding';
+import { BoundViewFactory, ViewSlot, TargetInstruction, customAttribute, bindable, templateController } from 'aurelia-templating';
+import { AbstractRepeater } from 'aurelia-templating-resources';
+import { getItemsSourceExpression, isOneTime, unwrapExpression, updateOneTimeBinding } from 'aurelia-templating-resources/repeat-utilities';
+import { viewsRequireLifecycle } from 'aurelia-templating-resources/analyze-view-factory';
+import { getStyleValue, calcOuterHeight, rebindAndMoveView } from './utilities';
+import { VirtualRepeatStrategyLocator } from './virtual-repeat-strategy-locator';
+import { ViewStrategyLocator } from './view-strategy';
+
+export let VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = inject(Element, BoundViewFactory, TargetInstruction, ViewSlot, ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator), _dec(_class = templateController(_class = _dec2(_class = (_class2 = class VirtualRepeat extends AbstractRepeater {
+ constructor(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
+ super({
+ local: 'item',
+ viewsRequireLifecycle: viewsRequireLifecycle(viewFactory)
+ });
+
+ this._first = 0;
+ this._previousFirst = 0;
+ this._viewsLength = 0;
+ this._lastRebind = 0;
+ this._topBufferHeight = 0;
+ this._bottomBufferHeight = 0;
+ this._bufferSize = 5;
+ this._scrollingDown = false;
+ this._scrollingUp = false;
+ this._switchedDirection = false;
+ this._isAttached = false;
+ this._ticking = false;
+ this._fixedHeightContainer = false;
+ this._hasCalculatedSizes = false;
+ this._isAtTop = true;
+
+ _initDefineProp(this, 'items', _descriptor, this);
+
+ _initDefineProp(this, 'local', _descriptor2, this);
+
+ this.element = element;
+ this.viewFactory = viewFactory;
+ this.instruction = instruction;
+ this.viewSlot = viewSlot;
+ this.observerLocator = observerLocator;
+ this.strategyLocator = strategyLocator;
+ this.viewStrategyLocator = viewStrategyLocator;
+ this.sourceExpression = getItemsSourceExpression(this.instruction, 'virtual-repeat.for');
+ this.isOneTime = isOneTime(this.sourceExpression);
+ }
+
+ attached() {
+ this._isAttached = true;
+ let element = this.element;
+ this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
+ this.scrollContainer = this.viewStrategy.getScrollContainer(element);
+ this.topBuffer = this.viewStrategy.createTopBufferElement(element);
+ this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
+ this.itemsChanged();
+ this.scrollListener = () => this._onScroll();
+ let containerStyle = this.scrollContainer.style;
+ if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
+ this._fixedHeightContainer = true;
+ this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ } else {
+ document.addEventListener('scroll', this.scrollListener);
+ }
+ }
+
+ bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext, overrideContext };
+ this._itemsLength = this.items.length;
+ }
+
+ call(context, changes) {
+ this[context](this.items, changes);
+ }
+
+ detached() {
+ this.scrollContainer.removeEventListener('scroll', this.scrollListener);
+ this._first = 0;
+ this._previousFirst = 0;
+ this._viewsLength = 0;
+ this._lastRebind = 0;
+ this._topBufferHeight = 0;
+ this._bottomBufferHeight = 0;
+ this._scrollingDown = false;
+ this._scrollingUp = false;
+ this._switchedDirection = false;
+ this._isAttached = false;
+ this._ticking = false;
+ this._hasCalculatedSizes = false;
+ this.viewStrategy.removeBufferElements(this.element, this.topBuffer, this.bottomBuffer);
+ this.isLastIndex = false;
+ this.scrollContainer = null;
+ this.scrollContainerHeight = null;
+ this.removeAllViews(true);
+ if (this.scrollHandler) {
+ this.scrollHandler.dispose();
+ }
+ this._unsubscribeCollection();
+ }
+
+ itemsChanged() {
+ this._unsubscribeCollection();
+
+ if (!this.scope) {
+ return;
+ }
+ let items = this.items;
+ this.strategy = this.strategyLocator.getStrategy(items);
+ if (items.length > 0) {
+ this.strategy.createFirstItem(this);
+ }
+ this._calcInitialHeights(items.length);
+ if (!this.isOneTime && !this._observeInnerCollection()) {
+ this._observeCollection();
+ }
+
+ this.strategy.instanceChanged(this, items, this._viewsLength);
+ }
+
+ unbind() {
+ this.scope = null;
+ this.items = null;
+ this._itemsLength = null;
+ }
+
+ handleCollectionMutated(collection, changes) {
+ this._handlingMutations = true;
+ this._itemsLength = collection.length;
+ this.strategy.instanceMutated(this, collection, changes);
+ }
+
+ handleInnerCollectionMutated(collection, changes) {
+ if (this.ignoreMutation) {
+ return;
+ }
+ this.ignoreMutation = true;
+ let newItems = this.sourceExpression.evaluate(this.scope, this.lookupFunctions);
+ this.observerLocator.taskQueue.queueMicroTask(() => this.ignoreMutation = false);
+
+ if (newItems === this.items) {
+ this.itemsChanged();
+ } else {
+ this.items = newItems;
+ }
+ }
+
+ _onScroll() {
+ if (!this._ticking && !this._handlingMutations) {
+ requestAnimationFrame(() => this._handleScroll());
+ this._ticking = true;
+ }
+
+ if (this._handlingMutations) {
+ this._handlingMutations = false;
+ }
+ }
+
+ _handleScroll() {
+ if (!this._isAttached) {
+ return;
+ }
+ let itemHeight = this.itemHeight;
+ let scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
+ this._first = Math.floor(scrollTop / itemHeight);
+ this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
+ this._checkScrolling();
+
+ if (this._scrollingDown) {
+ let viewsToMove = this._first - this._lastRebind;
+ if (this._switchedDirection) {
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ }
+ this._isAtTop = false;
+ this._lastRebind = this._first;
+ let movedViewsCount = this._moveViews(viewsToMove);
+ let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight + adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
+ if (this._bottomBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ } else if (this._scrollingUp) {
+ let viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ viewsToMove = this._bufferSize - (this._first - this._lastRebind);
+ }
+ }
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ let movedViewsCount = this._moveViews(viewsToMove);
+ this.movedViewsCount = movedViewsCount;
+ let adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
+ this._previousFirst = this._first;
+
+ this._ticking = false;
+ }
+
+ _checkScrolling() {
+ if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
+ if (!this._scrollingDown) {
+ this._scrollingDown = true;
+ this._scrollingUp = false;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
+ if (!this._scrollingUp) {
+ this._scrollingDown = false;
+ this._scrollingUp = true;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else {
+ this._isScrolling = false;
+ }
+ }
+
+ _adjustBufferHeights() {
+ this.topBuffer.setAttribute('style', `height: ${ this._topBufferHeight }px`);
+ this.bottomBuffer.setAttribute('style', `height: ${ this._bottomBufferHeight }px`);
+ }
+
+ _unsubscribeCollection() {
+ if (this.collectionObserver) {
+ this.collectionObserver.unsubscribe(this.callContext, this);
+ this.collectionObserver = null;
+ this.callContext = null;
+ }
+ }
+
+ _moveViews(length) {
+ let getNextIndex = this._scrollingDown ? (index, i) => index + i : (index, i) => index - i;
+ let isAtFirstOrLastIndex = () => this._scrollingDown ? this.isLastIndex : this._isAtTop;
+ let childrenLength = this.viewCount();
+ let viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
+ let items = this.items;
+ let index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
+ let i = 0;
+ while (i < length && !isAtFirstOrLastIndex()) {
+ let view = this.view(viewIndex);
+ let nextIndex = getNextIndex(index, i);
+ this.isLastIndex = nextIndex >= items.length - 1;
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
+ rebindAndMoveView(this, view, nextIndex, this._scrollingDown);
+ i++;
+ }
+ }
+
+ return length - (length - i);
+ }
+
+ _getIndexOfLastView() {
+ return this.view(this.viewCount() - 1).overrideContext.$index;
+ }
+
+ _getIndexOfFirstView() {
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
+ }
+
+ _calcInitialHeights(itemsLength) {
+ if (this._viewsLength > 0 && this._itemsLength === itemsLength || itemsLength <= 0) {
+ return;
+ }
+ this._hasCalculatedSizes = true;
+ this._itemsLength = itemsLength;
+ let firstViewElement = this.view(0).firstChild.nextElementSibling;
+ this.itemHeight = calcOuterHeight(firstViewElement);
+ if (this.itemHeight <= 0) {
+ throw new Error('Could not calculate item height');
+ }
+ this.scrollContainerHeight = this._fixedHeightContainer ? this._calcScrollHeight(this.scrollContainer) : document.documentElement.clientHeight;
+ this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
+ this._viewsLength = this.elementsInView * 2 + this._bufferSize;
+ this._bottomBufferHeight = this.itemHeight * itemsLength - this.itemHeight * this._viewsLength;
+ if (this._bottomBufferHeight < 0) {
+ this._bottomBufferHeight = 0;
+ }
+ this.bottomBuffer.setAttribute('style', `height: ${ this._bottomBufferHeight }px`);
+ this._topBufferHeight = 0;
+ this.topBuffer.setAttribute('style', `height: ${ this._topBufferHeight }px`);
+
+ this.scrollContainer.scrollTop = 0;
+ this._first = 0;
+ }
+
+ _calcScrollHeight(element) {
+ let height;
+ height = element.getBoundingClientRect().height;
+ height -= getStyleValue(element, 'borderTopWidth');
+ height -= getStyleValue(element, 'borderBottomWidth');
+ return height;
+ }
+
+ _observeInnerCollection() {
+ let items = this._getInnerCollection();
+ let strategy = this.strategyLocator.getStrategy(items);
+ if (!strategy) {
+ return false;
+ }
+ this.collectionObserver = strategy.getCollectionObserver(this.observerLocator, items);
+ if (!this.collectionObserver) {
+ return false;
+ }
+ this.callContext = 'handleInnerCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ return true;
+ }
+
+ _getInnerCollection() {
+ let expression = unwrapExpression(this.sourceExpression);
+ if (!expression) {
+ return null;
+ }
+ return expression.evaluate(this.scope, null);
+ }
+
+ _observeCollection() {
+ let items = this.items;
+ this.collectionObserver = this.strategy.getCollectionObserver(this.observerLocator, items);
+ if (this.collectionObserver) {
+ this.callContext = 'handleCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ }
+ }
+
+ viewCount() {
+ return this.viewSlot.children.length;
+ }
+ views() {
+ return this.viewSlot.children;
+ }
+ view(index) {
+ return this.viewSlot.children[index];
+ }
+
+ addView(bindingContext, overrideContext) {
+ let view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ }
+
+ insertView(index, bindingContext, overrideContext) {
+ let view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ }
+
+ removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ }
+
+ removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ }
+
+ updateBindings(view) {
+ let j = view.bindings.length;
+ while (j--) {
+ updateOneTimeBinding(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ let k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ let binding = view.controllers[j].boundProperties[k].binding;
+ updateOneTimeBinding(binding);
+ }
+ }
+ }
+}, (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [bindable], {
+ enumerable: true,
+ initializer: null
+}), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, 'local', [bindable], {
+ enumerable: true,
+ initializer: null
+})), _class2)) || _class) || _class) || _class);
\ No newline at end of file
diff --git a/dist/es6/array-virtual-repeat-strategy.js b/dist/es6/array-virtual-repeat-strategy.js
deleted file mode 100644
index 6ffc78f..0000000
--- a/dist/es6/array-virtual-repeat-strategy.js
+++ /dev/null
@@ -1,220 +0,0 @@
-import {ArrayRepeatStrategy} from 'aurelia-templating-resources/array-repeat-strategy';
-import {createFullOverrideContext, updateOverrideContexts, updateOverrideContext, updateOneTimeBinding} from 'aurelia-templating-resources/repeat-utilities';
-
-/**
-* A strategy for repeating a template over an array.
-*/
-export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
- // create first item to calculate the heights
- createFirstItem(repeat) {
- var overrideContext = createFullOverrideContext(repeat, repeat.items[0], 0, 1);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
- }
- /**
- * Handle the repeat's collection instance changing.
- * @param repeat The repeater instance.
- * @param items The new array instance.
- */
- instanceChanged(repeat, items) {
- this._inPlaceProcessItems(repeat, items);
- }
-
- _standardProcessInstanceChanged(repeat, items) {
- for(var i = 1, ii = repeat._viewsLength; i < ii; ++i){
- let overrideContext = createFullOverrideContext(repeat, items[i], i, ii);
- let view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
- }
- }
-
- _inPlaceProcessItems(repeat, items) {
- let itemsLength = items.length;
- let viewsLength = repeat.viewSlot.children.length;
- let first = repeat._getIndexOfFirstView();
- // remove unneeded views.
- while (viewsLength > repeat._viewsLength) {
- viewsLength--;
- repeat.viewSlot.removeAt(viewsLength, true);
- }
- // avoid repeated evaluating the property-getter for the "local" property.
- let local = repeat.local;
- // re-evaluate bindings on existing views.
- for (let i = 0; i < viewsLength; i++) {
- let view = repeat.viewSlot.children[i];
- let last = i === itemsLength - 1;
- let middle = i !== 0 && !last;
- // any changes to the binding context?
- if (view.bindingContext[local] === items[i + first] && view.overrideContext.$middle === middle && view.overrideContext.$last === last) {
- // no changes. continue...
- continue;
- }
- // update the binding context and refresh the bindings.
- view.bindingContext[local] = items[i + first];
- view.overrideContext.$middle = middle;
- view.overrideContext.$last = last;
- let j = view.bindings.length;
- while (j--) {
- updateOneTimeBinding(view.bindings[j]);
- }
- j = view.controllers.length;
- while (j--) {
- let k = view.controllers[j].boundProperties.length;
- while (k--) {
- let binding = view.controllers[j].boundProperties[k].binding;
- updateOneTimeBinding(binding);
- }
- }
- }
- // add new views
- for (let i = viewsLength; i < repeat._viewsLength; i++) {
- let overrideContext = createFullOverrideContext(repeat, items[i], i, itemsLength);
- let view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
- }
- }
-
- /**
- * Handle the repeat's collection instance mutating.
- * @param repeat The repeat instance.
- * @param array The modified array.
- * @param splices Records of array changes.
- */
- instanceMutated(repeat, array, splices) {
- this._updateViews(repeat, repeat.items, splices);
- }
-
- _standardProcessInstanceMutated(repeat, array, splices) {
- let removeDelta = 0;
- let viewSlot = repeat.viewSlot;
- let rmPromises = [];
-
- for (let i = 0, ii = splices.length; i < ii; ++i) {
- let splice = splices[i];
- let removed = splice.removed;
- let viewIndex = this._getViewIndex(repeat, viewSlot, splice.index);
- if (viewIndex >= 0) {
- for (let j = 0, jj = removed.length; j < jj; ++j) {
- let viewOrPromise = viewSlot.removeAt(viewIndex + removeDelta + rmPromises.length, true);
-
- // TODO Create view without trigger view lifecycle - or better solution
- let length = viewSlot.children.length;
- let overrideContext = createFullOverrideContext(repeat, repeat.items[length], length, repeat.items.length);
- let view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.isAttached = false;
- repeat.viewSlot.add(view);
- repeat.viewSlot.isAttached = true;
-
- if (viewOrPromise instanceof Promise) {
- rmPromises.push(viewOrPromise);
- }
- }
- removeDelta -= splice.addedCount;
- }
- }
-
- if (rmPromises.length > 0) {
- Promise.all(rmPromises).then(() => {
- this._handleAddedSplices(repeat, array, splices);
- this._updateViews(repeat, array, splices);
- });
- } else {
- this._handleAddedSplices(repeat, array, splices);
- this._updateViews(repeat, array, splices);
- }
- }
-
- _updateViews(repeat, items, splices) {
- let totalAdded = 0;
- let totalRemoved = 0;
- repeat.items = items;
-
- for(let i = 0, ii = splices.length; i < ii; ++i){
- let splice = splices[0];
- totalAdded += splice.addedCount;
- totalRemoved += splice.removed.length;
- }
-
- let index = repeat._getIndexOfFirstView() - totalRemoved;
-
- if(index < 0) {
- index = 0;
- }
-
- let viewSlot = repeat.viewSlot;
-
- for(let i = 0, ii = viewSlot.children.length; i < ii; ++i){
- let view = viewSlot.children[i];
- let nextIndex = index + i;
- let itemsLength = items.length;
- if((nextIndex) <= itemsLength - 1) {
- view.bindingContext[repeat.local] = items[nextIndex];
- updateOverrideContext(view.overrideContext, nextIndex, itemsLength);
- }
- }
-
- let bufferDelta = repeat.itemHeight * totalAdded + repeat.itemHeight * -totalRemoved;
-
- if(repeat._bottomBufferHeight + bufferDelta < 0) {
- repeat._topBufferHeight = repeat._topBufferHeight + bufferDelta;
- } else {
- repeat._bottomBufferHeight = repeat._bottomBufferHeight + bufferDelta;
- }
-
- if(repeat._bottomBufferHeight > 0) {
- repeat.isLastIndex = false;
- }
-
- repeat._adjustBufferHeights();
- }
-
- _handleAddedSplices(repeat, array, splices) {
- let spliceIndexLow;
- let arrayLength = array.length;
- for (let i = 0, ii = splices.length; i < ii; ++i) {
- let splice = splices[i];
- let addIndex = splice.index;
- let end = splice.index + splice.addedCount;
-
- if (typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index) {
- spliceIndexLow = addIndex;
- }
-
- for (; addIndex < end; ++addIndex) {
- let overrideContext = createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
- let view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.insert(addIndex, view);
- }
- }
-
- return spliceIndexLow;
- }
-
- _isIndexInDom(viewSlot, index) {
- if(viewSlot.children.length === 0) {
- return false;
- }
-
- let indexLow = viewSlot.children[0].overrideContext.$index;
- let indexHi = viewSlot.children[viewSlot.children.length - 1].overrideContext.$index;
-
- return index >= indexLow && index <= indexHi;
- }
-
- _getViewIndex(repeat, viewSlot, index) {
- if(viewSlot.children.length === 0) {
- return -1;
- }
- let indexLow = viewSlot.children[0].overrideContext.$index;
- let viewIndex = index - indexLow;
- if(viewIndex > repeat._viewsLength - 1) {
- viewIndex = -1;
- }
- return viewIndex;
- }
-}
diff --git a/dist/es6/index.js b/dist/es6/index.js
deleted file mode 100644
index 802ffc1..0000000
--- a/dist/es6/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import {VirtualRepeat} from './virtual-repeat';
-import {VirtualList} from './virtual-list';
-
-export function configure(config){
- config.globalResources(
- './virtual-repeat',
- './virtual-list'
- );
-}
-
-export {
- VirtualRepeat,
- VirtualList
-};
diff --git a/dist/es6/utilities.js b/dist/es6/utilities.js
deleted file mode 100644
index 1eaf745..0000000
--- a/dist/es6/utilities.js
+++ /dev/null
@@ -1,32 +0,0 @@
-export function calcOuterHeight(element){
- var height;
- height = element.getBoundingClientRect().height;
- height += getStyleValue(element, 'marginTop');
- height += getStyleValue(element, 'marginBottom');
- return height;
-}
-
-export function calcScrollHeight(element){
- var height;
- height = element.getBoundingClientRect().height;
- height -= getStyleValue(element, 'borderTopWidth');
- height -= getStyleValue(element, 'borderBottomWidth');
- return height;
-}
-
-export function insertBeforeNode(view, scrollView, node) {
- let viewStart = view.firstChild;
- let element = viewStart.nextSibling;
- let viewEnd = view.lastChild;
-
- scrollView.insertBefore(viewEnd, node);
- scrollView.insertBefore(element, viewEnd);
- scrollView.insertBefore(viewStart, element);
-}
-
-function getStyleValue(element, style){
- var currentStyle, styleValue;
- currentStyle = element.currentStyle || window.getComputedStyle(element);
- styleValue = parseInt(currentStyle[style]);
- return Number.isNaN(styleValue) ? 0 : styleValue;
-}
diff --git a/dist/es6/view-strategy.js b/dist/es6/view-strategy.js
deleted file mode 100644
index 67c1895..0000000
--- a/dist/es6/view-strategy.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import {insertBeforeNode} from './utilities';
-
-export class ViewStrategyLocator {
- getStrategy(element) {
- if (element.parentNode.localName === 'tbody') {
- return new TableStrategy();
- } else {
- return new DefaultStrategy();
- }
- }
-}
-
-export class TableStrategy {
- getScrollList(element) {
- return element.parentNode;
- }
-
- getScrollContainer(element) {
- return this.getScrollList(element).parentElement.parentElement;
- }
-
- moveViewFirst(view, scrollElement) {
- insertBeforeNode(view, scrollElement, scrollElement.childNodes[2]);
- }
-
- moveViewLast(view, scrollElement, childrenLength) {
- insertBeforeNode(view, scrollElement, scrollElement.children[childrenLength + 1]);
- }
-
- createTopBufferElement(scrollList, element) {
- let tr = document.createElement('tr');
- let buffer = document.createElement('td');
- buffer.setAttribute("style","height: 0px");
- tr.appendChild(buffer);
- scrollList.insertBefore(tr, element);
- return buffer;
- }
-
- createBottomBufferElement(scrollList, element) {
- let tr = document.createElement('tr');
- let buffer = document.createElement('td');
- buffer.setAttribute("style","height: 0px");
- tr.appendChild(buffer);
- element.parentNode.insertBefore(tr, element.nextSibling);
- return buffer;
- }
-
- removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer.parentElement);
- scrollList.removeChild(bottomBuffer.parentElement);
- }
-}
-
-export class DefaultStrategy {
- getScrollList(element) {
- return element.parentNode;
- }
-
- getScrollContainer(element) {
- return this.getScrollList(element).parentElement;
- }
-
- moveViewFirst(view, scrollElement) {
- insertBeforeNode(view, scrollElement, scrollElement.childNodes[2]);
- }
-
- moveViewLast(view, scrollElement, childrenLength) {
- insertBeforeNode(view, scrollElement, scrollElement.children[childrenLength + 1]);
- }
-
- createTopBufferElement(scrollList, element) {
- let elementName = scrollList.localName === 'ul' ? 'li' : 'div';
- let buffer = document.createElement(elementName);
- buffer.setAttribute("style","height: 0px");
- scrollList.insertBefore(buffer, element);
- return buffer;
- }
-
- createBottomBufferElement(scrollList, element) {
- let elementName = scrollList.localName === 'ul' ? 'li' : 'div';
- let buffer = document.createElement(elementName);
- buffer.setAttribute("style","height: 0px");
- element.parentNode.insertBefore(buffer, element.nextSibling);
- return buffer;
- }
-
- removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer);
- scrollList.removeChild(bottomBuffer);
- }
-}
diff --git a/dist/es6/virtual-list.html b/dist/es6/virtual-list.html
deleted file mode 100644
index fcba809..0000000
--- a/dist/es6/virtual-list.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/dist/es6/virtual-list.js b/dist/es6/virtual-list.js
deleted file mode 100644
index 6d06fed..0000000
--- a/dist/es6/virtual-list.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import {bindable} from 'aurelia-templating';
-
-export class VirtualList {
- @bindable items
-
- bind(bindingContext, overrideContext){
- this.$parent = bindingContext;
- }
-}
diff --git a/dist/es6/virtual-repeat-strategy-locator.js b/dist/es6/virtual-repeat-strategy-locator.js
deleted file mode 100644
index 025d526..0000000
--- a/dist/es6/virtual-repeat-strategy-locator.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import {RepeatStrategyLocator} from 'aurelia-templating-resources/repeat-strategy-locator';
-import {ArrayVirtualRepeatStrategy} from './array-virtual-repeat-strategy';
-
-export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
- constructor() {
- super();
- this.matchers = [];
- this.strategies = [];
-
- this.addStrategy(items => items instanceof Array, new ArrayVirtualRepeatStrategy());
- }
-}
diff --git a/dist/es6/virtual-repeat.js b/dist/es6/virtual-repeat.js
deleted file mode 100644
index 2a8b92f..0000000
--- a/dist/es6/virtual-repeat.js
+++ /dev/null
@@ -1,391 +0,0 @@
-import {inject} from 'aurelia-dependency-injection';
-import {
- ObserverLocator,
- calcSplices,
- getChangeRecords,
- createOverrideContext
-} from 'aurelia-binding';
-import {
- BoundViewFactory,
- ViewSlot,
- TargetInstruction,
- customAttribute,
- bindable,
- templateController
-} from 'aurelia-templating';
-import {
- updateOverrideContext,
- createFullOverrideContext,
- updateOverrideContexts,
- getItemsSourceExpression,
- isOneTime,
- unwrapExpression
-} from 'aurelia-templating-resources/repeat-utilities';
-import {viewsRequireLifecycle} from 'aurelia-templating-resources/analyze-view-factory';
-import {
- calcScrollHeight,
- calcOuterHeight,
- getNthNode,
- moveViewFirst,
- moveViewLast
-} from './utilities';
-import {VirtualRepeatStrategyLocator} from './virtual-repeat-strategy-locator';
-import {ViewStrategyLocator} from './view-strategy';
-
-@customAttribute('virtual-repeat')
-@templateController
-@inject(Element, BoundViewFactory, TargetInstruction, ViewSlot, ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator)
-export class VirtualRepeat {
- _first = 0;
- _previousFirst = 0;
- _viewsLength = 0;
- _lastRebind = 0;
- _topBufferHeight = 0;
- _bottomBufferHeight = 0;
- _bufferSize = 5;
- _scrollingDown = false;
- _scrollingUp = false;
- _switchedDirection = false;
- _isAttached = false;
- _ticking = false;
-
- @bindable items
- @bindable local
- constructor(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator){
- this.element = element;
- this.viewFactory = viewFactory;
- this.instruction = instruction;
- this.viewSlot = viewSlot;
- this.observerLocator = observerLocator;
- this.strategyLocator = strategyLocator;
- this.viewStrategyLocator = viewStrategyLocator;
- this.local = 'item';
- this.sourceExpression = getItemsSourceExpression(this.instruction, 'virtual-repeat.for');
- this.isOneTime = isOneTime(this.sourceExpression);
- this.viewsRequireLifecycle = viewsRequireLifecycle(viewFactory);
- }
-
- attached(){
- this._isAttached = true;
- let element = this.element;
- this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
- this.scrollList = this.viewStrategy.getScrollList(element);
- this.scrollContainer = this.viewStrategy.getScrollContainer(element);
- this.topBuffer = this.viewStrategy.createTopBufferElement(this.scrollList, element);
- this.bottomBuffer = this.viewStrategy.createBottomBufferElement(this.scrollList, element);
- this.itemsChanged();
- this.scrollListener = () => this._onScroll();
- this.scrollContainer.addEventListener('scroll', this.scrollListener);
- }
-
- bind(bindingContext, overrideContext){
- this.scope = { bindingContext, overrideContext };
- this._itemsLength = this.items.length;
-
- // TODO Fix this
- window.onresize = () => { this._handleResize(); };
- }
-
- call(context, changes) {
- this[context](this.items, changes);
- }
-
- detached() {
- this.scrollContainer.removeEventListener('scroll', this.scrollListener);
- this._first = 0;
- this._previousFirst = 0;
- this._viewsLength = 0;
- this._lastRebind = 0;
- this._topBufferHeight = 0;
- this._bottomBufferHeight = 0;
- this._scrollingDown = false;
- this._scrollingUp = false;
- this._switchedDirection = false;
- this._isAttached = false;
- this._ticking = false;
- this.viewStrategy.removeBufferElements(this.scrollList, this.topBuffer, this.bottomBuffer);
- this.isLastIndex = false;
- this.scrollList = null;
- this.scrollContainer = null;
- this.scrollContainerHeight = null;
- this.viewSlot.removeAll(true);
- if(this.scrollHandler) {
- this.scrollHandler.dispose();
- }
- this._unsubscribeCollection();
-
- }
-
- itemsChanged() {
- this._unsubscribeCollection();
- // still bound?
- if (!this.scope) {
- return;
- }
- let items = this.items;
- this.strategy = this.strategyLocator.getStrategy(items);
- this.strategy.createFirstItem(this);
- this._calcInitialHeights();
- if (!this.isOneTime && !this._observeInnerCollection()) {
- this._observeCollection();
- }
-
- this.strategy.instanceChanged(this, items, this._viewsLength);
- }
-
- unbind(){
- this.scope = null;
- this.items = null;
- this._itemsLength = null;
- }
-
- handleCollectionMutated(collection, changes) {
- this._itemsLength = collection.length;
- this.strategy.instanceMutated(this, collection, changes);
- }
-
- handleInnerCollectionMutated(collection, changes) {
- // guard against source expressions that have observable side-effects that could
- // cause an infinite loop- eg a value converter that mutates the source array.
- if (this.ignoreMutation) {
- return;
- }
- this.ignoreMutation = true;
- let newItems = this.sourceExpression.evaluate(this.scope, this.lookupFunctions);
- this.observerLocator.taskQueue.queueMicroTask(() => this.ignoreMutation = false);
-
- // call itemsChanged...
- if (newItems === this.items) {
- // call itemsChanged directly.
- this.itemsChanged();
- } else {
- // call itemsChanged indirectly by assigning the new collection value to
- // the items property, which will trigger the self-subscriber to call itemsChanged.
- this.items = newItems;
- }
- }
-
- _onScroll() {
- if(!this._ticking) {
- requestAnimationFrame(() => this._handleScroll());
- this._ticking = true;
- }
- }
-
- _handleScroll() {
- if (!this._isAttached) {
- return;
- }
- let itemHeight = this.itemHeight;
- let scrollTop = this.scrollContainer.scrollTop;
- this._first = Math.floor(scrollTop / itemHeight);
- this._checkScrolling();
- // TODO if and else paths do almost same thing, refactor?
- // move views down?
- if(this._scrollingDown && (this._hasScrolledDownTheBuffer() || (this._switchedDirection && this._hasScrolledDownTheBufferFromTop()))) {
- let viewsToMove = this._first - this._lastRebind;
- if(this._switchedDirection) {
- viewsToMove = this.isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
- }
- this.isAtTop = false;
- this._lastRebind = this._first;
- let movedViewsCount = this._moveViews(viewsToMove);
- let adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
- var test = 0
- this._switchedDirection = false;
- this._topBufferHeight = this._topBufferHeight + adjustHeight;
- this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
- if (this._bottomBufferHeight >= 0) {
- this._adjustBufferHeights();
- }
- // move view up?
- } else if (this._scrollingUp && (this._hasScrolledUpTheBuffer() || (this._switchedDirection && this._hasScrolledUpTheBufferFromBottom()))) {
- let viewsToMove = this._lastRebind - this._first;
- if(this._switchedDirection) {
- if(this.isLastIndex) {
- viewsToMove = this.items.length - this._first - this.elementsInView;
- } else {
- viewsToMove = this._bufferSize - (this._first - this._lastRebind);
- }
- }
- this.isLastIndex = false;
- this._lastRebind = this._first;
- let movedViewsCount = this._moveViews(viewsToMove);
- this.movedViewsCount = movedViewsCount;
- let adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
- this._switchedDirection = false;
- this._topBufferHeight = this._topBufferHeight - adjustHeight;
- this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
- if (this._topBufferHeight >= 0) {
- this._adjustBufferHeights();
- }
- }
- this._previousFirst = this._first;
-
- this._ticking = false;
- }
-
- _handleResize() {
- var children = this.viewSlot.children,
- childrenLength = children.length,
- overrideContext, view, addIndex;
-
- this.scrollContainerHeight = calcScrollHeight(this.scrollContainer);
- this._viewsLength = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
-
- if(this._viewsLength > childrenLength){
- addIndex = children[childrenLength - 1].overrideContext.$index + 1;
- overrideContext = createFullOverrideContext(this, this.items[addIndex], addIndex, this.items.length);
- view = this.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- this.viewSlot.insert(childrenLength, view);
- }else if (this._viewsLength < childrenLength){
- this._viewsLength = childrenLength;
- }
- }
-
- _checkScrolling() {
- if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
- if (!this._scrollingDown) {
- this._scrollingDown = true;
- this._scrollingUp = false;
- this._switchedDirection = true;
- } else {
- this._switchedDirection = false;
- }
- this._isScrolling = true;
- } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this.isAtTop)) {
- if (!this._scrollingUp) {
- this._scrollingDown = false;
- this._scrollingUp = true;
- this._switchedDirection = true;
- } else {
- this._switchedDirection = false;
- }
- this._isScrolling = true;
- } else {
- this._isScrolling = false;
- }
- }
-
- _hasScrolledDownTheBuffer() {
- let atBottom = (this._first + this._viewsLength) >= this.items.length;
- let itemsAddedWhileAtBottom = atBottom && this._first > this._lastRebind;
- return this._first - this._lastRebind >= this._bufferSize || itemsAddedWhileAtBottom;
- }
-
- _hasScrolledDownTheBufferFromTop() {
- return this._first - this._bufferSize > 0;
- }
-
- _hasScrolledUpTheBuffer() {
- return this._lastRebind - this._first >= this._bufferSize;
- }
-
- _hasScrolledUpTheBufferFromBottom() {
- return this._first + this._bufferSize < this.items.length;
- }
-
- _adjustBufferHeights() {
- this.topBuffer.setAttribute('style', `height: ${this._topBufferHeight}px`);
- this.bottomBuffer.setAttribute("style", `height: ${this._bottomBufferHeight}px`);
- }
-
- _unsubscribeCollection() {
- if (this.collectionObserver) {
- this.collectionObserver.unsubscribe(this.callContext, this);
- this.collectionObserver = null;
- this.callContext = null;
- }
- }
-
- _moveViews(length) {
- let getNextIndex = this._scrollingDown ? (index, i) => index + i : (index, i) => index - i;
- let isAtFirstOrLastIndex = () => this._scrollingDown ? this.isLastIndex : this.isAtTop;
- let viewSlot = this.viewSlot;
- let childrenLength = viewSlot.children.length;
- let viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
- let items = this.items;
- let scrollList = this.scrollList;
- let index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
- let i = 0;
- while(i < length && !isAtFirstOrLastIndex()) {
- let view = viewSlot.children[viewIndex];
- let nextIndex = getNextIndex(index, i);
- updateOverrideContext(view.overrideContext, nextIndex, items.length);
- view.bindingContext[this.local] = items[nextIndex];
- if(this._scrollingDown) {
- viewSlot.children.push(viewSlot.children.shift());
- this.viewStrategy.moveViewLast(view, scrollList, childrenLength);
- this.isLastIndex = nextIndex >= items.length - 1;
- } else {
- viewSlot.children.unshift(viewSlot.children.splice(-1,1)[0]);
- this.viewStrategy.moveViewFirst(view, scrollList);
- this.isAtTop = nextIndex <= 0;
- }
- i++;
- }
- return length - (length - i);
- }
-
- _getIndexOfLastView(){
- let children = this.viewSlot.children;
- return children[children.length - 1].overrideContext.$index;
- }
-
- _getIndexOfFirstView(){
- let children = this.viewSlot.children;
- return children[0].overrideContext.$index;
- }
-
- _calcInitialHeights() {
- if (this._viewsLength > 0 && this._itemsLength == this.items.length) {
- return;
- }
- this._itemsLength = this.items.length;
- let listItems = this.scrollList.children;
- this.itemHeight = calcOuterHeight(listItems[1]);
- this.scrollContainerHeight = calcScrollHeight(this.scrollContainer);
- this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
- this._viewsLength = (this.elementsInView * 2) + this._bufferSize;
- this._bottomBufferHeight = this.itemHeight * this.items.length - this.itemHeight * this._viewsLength;
- this.bottomBuffer.setAttribute("style", `height: ${this._bottomBufferHeight}px`);
- this._topBufferHeight = 0;
- this.topBuffer.setAttribute("style", `height: ${this._topBufferHeight}px`);
- // TODO This will cause scrolling back to top when swapping collection instances that have different lengths - instead should keep the scroll position
- this.scrollContainer.scrollTop = 0;
- this._first = 0;
- }
-
- _observeInnerCollection() {
- let items = this._getInnerCollection();
- let strategy = this.strategyLocator.getStrategy(items);
- if (!strategy) {
- return false;
- }
- this.collectionObserver = strategy.getCollectionObserver(this.observerLocator, items);
- if (!this.collectionObserver) {
- return false;
- }
- this.callContext = 'handleInnerCollectionMutated';
- this.collectionObserver.subscribe(this.callContext, this);
- return true;
- }
-
- _getInnerCollection() {
- let expression = unwrapExpression(this.sourceExpression);
- if (!expression) {
- return null;
- }
- return expression.evaluate(this.scope, null);
- }
-
- _observeCollection() {
- let items = this.items;
- this.collectionObserver = this.strategy.getCollectionObserver(this.observerLocator, items);
- if (this.collectionObserver) {
- this.callContext = 'handleCollectionMutated';
- this.collectionObserver.subscribe(this.callContext, this);
- }
- }
-}
diff --git a/dist/system/array-virtual-repeat-strategy.js b/dist/system/array-virtual-repeat-strategy.js
index 098f337..eca90da 100644
--- a/dist/system/array-virtual-repeat-strategy.js
+++ b/dist/system/array-virtual-repeat-strategy.js
@@ -1,36 +1,61 @@
-System.register(['aurelia-templating-resources/array-repeat-strategy', 'aurelia-templating-resources/repeat-utilities'], function (_export) {
- 'use strict';
+'use strict';
- var ArrayRepeatStrategy, createFullOverrideContext, updateOverrideContexts, updateOverrideContext, updateOneTimeBinding, ArrayVirtualRepeatStrategy;
+System.register(['aurelia-templating-resources/array-repeat-strategy', 'aurelia-templating-resources/repeat-utilities', './utilities'], function (_export, _context) {
+ var ArrayRepeatStrategy, createFullOverrideContext, updateVirtualOverrideContexts, rebindAndMoveView, getElementDistanceToBottomViewPort, ArrayVirtualRepeatStrategy;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
- function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
return {
setters: [function (_aureliaTemplatingResourcesArrayRepeatStrategy) {
ArrayRepeatStrategy = _aureliaTemplatingResourcesArrayRepeatStrategy.ArrayRepeatStrategy;
}, function (_aureliaTemplatingResourcesRepeatUtilities) {
createFullOverrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext;
- updateOverrideContexts = _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContexts;
- updateOverrideContext = _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext;
- updateOneTimeBinding = _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding;
+ }, function (_utilities) {
+ updateVirtualOverrideContexts = _utilities.updateVirtualOverrideContexts;
+ rebindAndMoveView = _utilities.rebindAndMoveView;
+ getElementDistanceToBottomViewPort = _utilities.getElementDistanceToBottomViewPort;
}],
execute: function () {
- ArrayVirtualRepeatStrategy = (function (_ArrayRepeatStrategy) {
+ _export('ArrayVirtualRepeatStrategy', ArrayVirtualRepeatStrategy = function (_ArrayRepeatStrategy) {
_inherits(ArrayVirtualRepeatStrategy, _ArrayRepeatStrategy);
function ArrayVirtualRepeatStrategy() {
_classCallCheck(this, ArrayVirtualRepeatStrategy);
- _ArrayRepeatStrategy.apply(this, arguments);
+ return _possibleConstructorReturn(this, _ArrayRepeatStrategy.apply(this, arguments));
}
ArrayVirtualRepeatStrategy.prototype.createFirstItem = function createFirstItem(repeat) {
var overrideContext = createFullOverrideContext(repeat, repeat.items[0], 0, 1);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
};
ArrayVirtualRepeatStrategy.prototype.instanceChanged = function instanceChanged(repeat, items) {
@@ -40,26 +65,24 @@ System.register(['aurelia-templating-resources/array-repeat-strategy', 'aurelia-
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceChanged = function _standardProcessInstanceChanged(repeat, items) {
for (var i = 1, ii = repeat._viewsLength; i < ii; ++i) {
var overrideContext = createFullOverrideContext(repeat, items[i], i, ii);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype._inPlaceProcessItems = function _inPlaceProcessItems(repeat, items) {
var itemsLength = items.length;
- var viewsLength = repeat.viewSlot.children.length;
+ var viewsLength = repeat.viewCount();
var first = repeat._getIndexOfFirstView();
while (viewsLength > repeat._viewsLength) {
viewsLength--;
- repeat.viewSlot.removeAt(viewsLength, true);
+ repeat.removeView(viewsLength, true);
}
var local = repeat.local;
for (var i = 0; i < viewsLength; i++) {
- var view = repeat.viewSlot.children[i];
+ var view = repeat.view(i);
var last = i === itemsLength - 1;
var middle = i !== 0 && !last;
@@ -70,166 +93,195 @@ System.register(['aurelia-templating-resources/array-repeat-strategy', 'aurelia-
view.bindingContext[local] = items[i + first];
view.overrideContext.$middle = middle;
view.overrideContext.$last = last;
- var j = view.bindings.length;
- while (j--) {
- updateOneTimeBinding(view.bindings[j]);
- }
- j = view.controllers.length;
- while (j--) {
- var k = view.controllers[j].boundProperties.length;
- while (k--) {
- var binding = view.controllers[j].boundProperties[k].binding;
- updateOneTimeBinding(binding);
- }
- }
+ repeat.updateBindings(view);
}
- for (var i = viewsLength; i < repeat._viewsLength; i++) {
- var overrideContext = createFullOverrideContext(repeat, items[i], i, itemsLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.add(view);
+ var minLength = Math.min(repeat._viewsLength, items.length);
+ for (var _i = viewsLength; _i < minLength; _i++) {
+ var overrideContext = createFullOverrideContext(repeat, items[_i], _i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
}
};
ArrayVirtualRepeatStrategy.prototype.instanceMutated = function instanceMutated(repeat, array, splices) {
- this._updateViews(repeat, repeat.items, splices);
+ this._standardProcessInstanceMutated(repeat, array, splices);
};
ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceMutated = function _standardProcessInstanceMutated(repeat, array, splices) {
- var _this = this;
+ var _this2 = this;
+
+ if (repeat.__queuedSplices) {
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var _splices$i = splices[i];
+ var index = _splices$i.index;
+ var removed = _splices$i.removed;
+ var addedCount = _splices$i.addedCount;
+
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ var maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ (function () {
+ var queuedSplices = repeat.__queuedSplices = [];
+
+ var runQueuedSplices = function runQueuedSplices() {
+ if (!queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ var nextPromise = _this2._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ })();
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._runSplices = function _runSplices(repeat, array, splices) {
+ var _this3 = this;
var removeDelta = 0;
- var viewSlot = repeat.viewSlot;
var rmPromises = [];
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var removed = splice.removed;
- var viewIndex = this._getViewIndex(repeat, viewSlot, splice.index);
- if (viewIndex >= 0) {
- for (var j = 0, jj = removed.length; j < jj; ++j) {
- var viewOrPromise = viewSlot.removeAt(viewIndex + removeDelta + rmPromises.length, true);
-
- var _length = viewSlot.children.length;
- var overrideContext = createFullOverrideContext(repeat, repeat.items[_length], _length, repeat.items.length);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.isAttached = false;
- repeat.viewSlot.add(view);
- repeat.viewSlot.isAttached = true;
-
- if (viewOrPromise instanceof Promise) {
- rmPromises.push(viewOrPromise);
- }
+ for (var j = 0, jj = removed.length; j < jj; ++j) {
+ var viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
}
- removeDelta -= splice.addedCount;
}
+ removeDelta -= splice.addedCount;
}
if (rmPromises.length > 0) {
- Promise.all(rmPromises).then(function () {
- _this._handleAddedSplices(repeat, array, splices);
- _this._updateViews(repeat, array, splices);
+ return Promise.all(rmPromises).then(function () {
+ _this3._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
});
- } else {
- this._handleAddedSplices(repeat, array, splices);
- this._updateViews(repeat, array, splices);
}
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
};
- ArrayVirtualRepeatStrategy.prototype._updateViews = function _updateViews(repeat, items, splices) {
- var totalAdded = 0;
- var totalRemoved = 0;
- repeat.items = items;
-
- for (var i = 0, ii = splices.length; i < ii; ++i) {
- var splice = splices[0];
- totalAdded += splice.addedCount;
- totalRemoved += splice.removed.length;
+ ArrayVirtualRepeatStrategy.prototype._removeViewAt = function _removeViewAt(repeat, collectionIndex, returnToCache) {
+ var viewOrPromise = void 0;
+ var view = void 0;
+ var viewSlot = repeat.viewSlot;
+ var viewCount = repeat.viewCount();
+ var viewAddIndex = void 0;
+
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ var collectionAddIndex = void 0;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ var data = repeat.items[collectionAddIndex];
+ if (data) {
+ var overrideContext = createFullOverrideContext(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ rebindAndMoveView(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
}
- var index = repeat._getIndexOfFirstView() - totalRemoved;
-
- if (index < 0) {
- index = 0;
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(function () {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
}
- var viewSlot = repeat.viewSlot;
-
- for (var i = 0, ii = viewSlot.children.length; i < ii; ++i) {
- var view = viewSlot.children[i];
- var nextIndex = index + i;
- var itemsLength = items.length;
- if (nextIndex <= itemsLength - 1) {
- view.bindingContext[repeat.local] = items[nextIndex];
- updateOverrideContext(view.overrideContext, nextIndex, itemsLength);
- }
- }
+ repeat._adjustBufferHeights();
+ };
- var bufferDelta = repeat.itemHeight * totalAdded + repeat.itemHeight * -totalRemoved;
+ ArrayVirtualRepeatStrategy.prototype._isIndexBeforeViewSlot = function _isIndexBeforeViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ };
- if (repeat._bottomBufferHeight + bufferDelta < 0) {
- repeat._topBufferHeight = repeat._topBufferHeight + bufferDelta;
- } else {
- repeat._bottomBufferHeight = repeat._bottomBufferHeight + bufferDelta;
- }
+ ArrayVirtualRepeatStrategy.prototype._isIndexAfterViewSlot = function _isIndexAfterViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ };
- if (repeat._bottomBufferHeight > 0) {
- repeat.isLastIndex = false;
+ ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
+ if (repeat.viewCount() === 0) {
+ return -1;
}
- repeat._adjustBufferHeights();
+ var topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
};
ArrayVirtualRepeatStrategy.prototype._handleAddedSplices = function _handleAddedSplices(repeat, array, splices) {
- var spliceIndexLow = undefined;
var arrayLength = array.length;
+ var viewSlot = repeat.viewSlot;
for (var i = 0, ii = splices.length; i < ii; ++i) {
var splice = splices[i];
var addIndex = splice.index;
var end = splice.index + splice.addedCount;
-
- if (typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index) {
- spliceIndexLow = addIndex;
- }
-
for (; addIndex < end; ++addIndex) {
- var overrideContext = createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
- var view = repeat.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- repeat.viewSlot.insert(addIndex, view);
+ var hasDistanceToBottomViewPort = getElementDistanceToBottomViewPort(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || !this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex) || hasDistanceToBottomViewPort) {
+ var overrideContext = createFullOverrideContext(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
}
}
-
- return spliceIndexLow;
- };
-
- ArrayVirtualRepeatStrategy.prototype._isIndexInDom = function _isIndexInDom(viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return false;
- }
-
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var indexHi = viewSlot.children[viewSlot.children.length - 1].overrideContext.$index;
-
- return index >= indexLow && index <= indexHi;
- };
-
- ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
- if (viewSlot.children.length === 0) {
- return -1;
- }
- var indexLow = viewSlot.children[0].overrideContext.$index;
- var viewIndex = index - indexLow;
- if (viewIndex > repeat._viewsLength - 1) {
- viewIndex = -1;
- }
- return viewIndex;
+ repeat._adjustBufferHeights();
};
return ArrayVirtualRepeatStrategy;
- })(ArrayRepeatStrategy);
+ }(ArrayRepeatStrategy));
_export('ArrayVirtualRepeatStrategy', ArrayVirtualRepeatStrategy);
}
diff --git a/dist/system/aurelia-ui-virtualization.d.ts b/dist/system/aurelia-ui-virtualization.d.ts
new file mode 100644
index 0000000..cc50ca3
--- /dev/null
+++ b/dist/system/aurelia-ui-virtualization.d.ts
@@ -0,0 +1,131 @@
+declare module 'aurelia-ui-virtualization' {
+ import {
+ updateOverrideContext,
+ createFullOverrideContext,
+ getItemsSourceExpression,
+ isOneTime,
+ unwrapExpression,
+ updateOneTimeBinding
+ } from 'aurelia-templating-resources/repeat-utilities';
+ import {
+ ArrayRepeatStrategy
+ } from 'aurelia-templating-resources/array-repeat-strategy';
+ import {
+ RepeatStrategyLocator
+ } from 'aurelia-templating-resources/repeat-strategy-locator';
+ import {
+ inject
+ } from 'aurelia-dependency-injection';
+ import {
+ ObserverLocator
+ } from 'aurelia-binding';
+ import {
+ BoundViewFactory,
+ ViewSlot,
+ TargetInstruction,
+ customAttribute,
+ bindable,
+ templateController
+ } from 'aurelia-templating';
+ import {
+ AbstractRepeater
+ } from 'aurelia-templating-resources';
+ import {
+ viewsRequireLifecycle
+ } from 'aurelia-templating-resources/analyze-view-factory';
+ export function calcOuterHeight(element: any): any;
+ export function insertBeforeNode(view: any, bottomBuffer: any): any;
+
+ /**
+ * Update the override context.
+ * @param startIndex index in collection where to start updating.
+ */
+ export function updateVirtualOverrideContexts(repeat: any, startIndex: any): any;
+ export function rebindAndMoveView(repeat: VirtualRepeat, view: View, index: number, moveToBottom: boolean): void;
+ export function getStyleValue(element: any, style: any): any;
+ export function getElementDistanceToBottomViewPort(element: any): any;
+
+ /**
+ * A strategy for repeating a template over an array.
+ */
+ export class ArrayVirtualRepeatStrategy extends ArrayRepeatStrategy {
+
+ // create first item to calculate the heights
+ createFirstItem(repeat: any): any;
+
+ /**
+ * Handle the repeat's collection instance changing.
+ * @param repeat The repeater instance.
+ * @param items The new array instance.
+ */
+ instanceChanged(repeat: any, items: any): any;
+
+ /**
+ * Handle the repeat's collection instance mutating.
+ * @param repeat The repeat instance.
+ * @param array The modified array.
+ * @param splices Records of array changes.
+ */
+ instanceMutated(repeat: any, array: any, splices: any): any;
+ }
+ export class ViewStrategyLocator {
+ getStrategy(element: any): any;
+ }
+ export class TableStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class DefaultStrategy {
+ getScrollContainer(element: any): any;
+ moveViewFirst(view: any, topBuffer: any): any;
+ moveViewLast(view: any, bottomBuffer: any): any;
+ createTopBufferElement(element: any): any;
+ createBottomBufferElement(element: any): any;
+ removeBufferElements(element: any, topBuffer: any, bottomBuffer: any): any;
+ }
+ export class VirtualRepeatStrategyLocator extends RepeatStrategyLocator {
+ constructor();
+ }
+ export class VirtualRepeat extends AbstractRepeater {
+ _first: any;
+ _previousFirst: any;
+ _viewsLength: any;
+ _lastRebind: any;
+ _topBufferHeight: any;
+ _bottomBufferHeight: any;
+ _bufferSize: any;
+ _scrollingDown: any;
+ _scrollingUp: any;
+ _switchedDirection: any;
+ _isAttached: any;
+ _ticking: any;
+ _fixedHeightContainer: any;
+ _hasCalculatedSizes: any;
+ _isAtTop: any;
+ items: any;
+ local: any;
+ constructor(element: any, viewFactory: any, instruction: any, viewSlot: any, observerLocator: any, strategyLocator: any, viewStrategyLocator: any);
+ attached(): any;
+ bind(bindingContext: any, overrideContext: any): any;
+ call(context: any, changes: any): any;
+ detached(): any;
+ itemsChanged(): any;
+ unbind(): any;
+ handleCollectionMutated(collection: any, changes: any): any;
+ handleInnerCollectionMutated(collection: any, changes: any): any;
+
+ // @override AbstractRepeater
+ viewCount(): any;
+ views(): any;
+ view(index: any): any;
+ addView(bindingContext: any, overrideContext: any): any;
+ insertView(index: any, bindingContext: any, overrideContext: any): any;
+ removeAllViews(returnToCache: any, skipAnimation: any): any;
+ removeView(index: any, returnToCache: any, skipAnimation: any): any;
+ updateBindings(view: View): any;
+ }
+}
\ No newline at end of file
diff --git a/dist/system/index.js b/dist/system/index.js
index 0c9438f..a396a21 100644
--- a/dist/system/index.js
+++ b/dist/system/index.js
@@ -1,24 +1,19 @@
-System.register(['./virtual-repeat', './virtual-list'], function (_export) {
- 'use strict';
-
- var VirtualRepeat, VirtualList;
-
- _export('configure', configure);
-
- function configure(config) {
- config.globalResources('./virtual-repeat', './virtual-list');
- }
+'use strict';
+System.register(['./virtual-repeat'], function (_export, _context) {
+ var VirtualRepeat;
return {
setters: [function (_virtualRepeat) {
VirtualRepeat = _virtualRepeat.VirtualRepeat;
- }, function (_virtualList) {
- VirtualList = _virtualList.VirtualList;
}],
execute: function () {
- _export('VirtualRepeat', VirtualRepeat);
+ function configure(config) {
+ config.globalResources('./virtual-repeat');
+ }
+
+ _export('configure', configure);
- _export('VirtualList', VirtualList);
+ _export('VirtualRepeat', VirtualRepeat);
}
};
});
\ No newline at end of file
diff --git a/dist/system/utilities.js b/dist/system/utilities.js
index a90c6dc..7a8f459 100644
--- a/dist/system/utilities.js
+++ b/dist/system/utilities.js
@@ -1,46 +1,84 @@
-System.register([], function (_export) {
- 'use strict';
-
- _export('calcOuterHeight', calcOuterHeight);
-
- _export('calcScrollHeight', calcScrollHeight);
-
- _export('insertBeforeNode', insertBeforeNode);
-
- function calcOuterHeight(element) {
- var height;
- height = element.getBoundingClientRect().height;
- height += getStyleValue(element, 'marginTop');
- height += getStyleValue(element, 'marginBottom');
- return height;
- }
-
- function calcScrollHeight(element) {
- var height;
- height = element.getBoundingClientRect().height;
- height -= getStyleValue(element, 'borderTopWidth');
- height -= getStyleValue(element, 'borderBottomWidth');
- return height;
- }
-
- function insertBeforeNode(view, scrollView, node) {
- var viewStart = view.firstChild;
- var element = viewStart.nextSibling;
- var viewEnd = view.lastChild;
-
- scrollView.insertBefore(viewEnd, node);
- scrollView.insertBefore(element, viewEnd);
- scrollView.insertBefore(viewStart, element);
- }
-
- function getStyleValue(element, style) {
- var currentStyle, styleValue;
- currentStyle = element.currentStyle || window.getComputedStyle(element);
- styleValue = parseInt(currentStyle[style]);
- return Number.isNaN(styleValue) ? 0 : styleValue;
- }
+'use strict';
+
+System.register(['aurelia-templating-resources/repeat-utilities'], function (_export, _context) {
+ var updateOverrideContext;
return {
- setters: [],
- execute: function () {}
+ setters: [function (_aureliaTemplatingResourcesRepeatUtilities) {
+ updateOverrideContext = _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext;
+ }],
+ execute: function () {
+ function calcOuterHeight(element) {
+ var height = void 0;
+ height = element.getBoundingClientRect().height;
+ height += getStyleValue(element, 'marginTop');
+ height += getStyleValue(element, 'marginBottom');
+ return height;
+ }
+
+ _export('calcOuterHeight', calcOuterHeight);
+
+ function insertBeforeNode(view, bottomBuffer) {
+ var viewStart = view.firstChild;
+ var element = viewStart.nextSibling;
+ var viewEnd = view.lastChild;
+ var parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+ }
+
+ _export('insertBeforeNode', insertBeforeNode);
+
+ function updateVirtualOverrideContexts(repeat, startIndex) {
+ var views = repeat.viewSlot.children;
+ var viewLength = views.length;
+ var collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ var delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ updateOverrideContext(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+ }
+
+ _export('updateVirtualOverrideContexts', updateVirtualOverrideContexts);
+
+ function rebindAndMoveView(repeat, view, index, moveToBottom) {
+ var items = repeat.items;
+ var viewSlot = repeat.viewSlot;
+ updateOverrideContext(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
+ }
+
+ _export('rebindAndMoveView', rebindAndMoveView);
+
+ function getStyleValue(element, style) {
+ var currentStyle = void 0;
+ var styleValue = void 0;
+ currentStyle = element.currentStyle || window.getComputedStyle(element);
+ styleValue = parseInt(currentStyle[style], 10);
+ return Number.isNaN(styleValue) ? 0 : styleValue;
+ }
+
+ _export('getStyleValue', getStyleValue);
+
+ function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
+ }
+
+ _export('getElementDistanceToBottomViewPort', getElementDistanceToBottomViewPort);
+ }
};
});
\ No newline at end of file
diff --git a/dist/system/view-strategy.js b/dist/system/view-strategy.js
index b1e6f2d..c6e575c 100644
--- a/dist/system/view-strategy.js
+++ b/dist/system/view-strategy.js
@@ -1,16 +1,20 @@
-System.register(['./utilities'], function (_export) {
- 'use strict';
+'use strict';
+System.register(['./utilities'], function (_export, _context) {
var insertBeforeNode, ViewStrategyLocator, TableStrategy, DefaultStrategy;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
return {
setters: [function (_utilities) {
insertBeforeNode = _utilities.insertBeforeNode;
}],
execute: function () {
- ViewStrategyLocator = (function () {
+ _export('ViewStrategyLocator', ViewStrategyLocator = function () {
function ViewStrategyLocator() {
_classCallCheck(this, ViewStrategyLocator);
}
@@ -18,109 +22,102 @@ System.register(['./utilities'], function (_export) {
ViewStrategyLocator.prototype.getStrategy = function getStrategy(element) {
if (element.parentNode.localName === 'tbody') {
return new TableStrategy();
- } else {
- return new DefaultStrategy();
}
+ return new DefaultStrategy();
};
return ViewStrategyLocator;
- })();
+ }());
_export('ViewStrategyLocator', ViewStrategyLocator);
- TableStrategy = (function () {
+ _export('TableStrategy', TableStrategy = function () {
function TableStrategy() {
_classCallCheck(this, TableStrategy);
}
- TableStrategy.prototype.getScrollList = function getScrollList(element) {
- return element.parentNode;
- };
-
TableStrategy.prototype.getScrollContainer = function getScrollContainer(element) {
- return this.getScrollList(element).parentElement.parentElement;
+ return element.parentNode;
};
- TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, scrollElement) {
- insertBeforeNode(view, scrollElement, scrollElement.childNodes[2]);
+ TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.parentElement.nextElementSibling.previousSibling);
};
- TableStrategy.prototype.moveViewLast = function moveViewLast(view, scrollElement, childrenLength) {
- insertBeforeNode(view, scrollElement, scrollElement.children[childrenLength + 1]);
+ TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
+ insertBeforeNode(view, bottomBuffer.parentElement);
};
- TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(scrollList, element) {
+ TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
var tr = document.createElement('tr');
var buffer = document.createElement('td');
- buffer.setAttribute("style", "height: 0px");
+ buffer.setAttribute('style', 'height: 0px');
tr.appendChild(buffer);
- scrollList.insertBefore(tr, element);
+ element.parentElement.insertBefore(tr, element);
return buffer;
};
- TableStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(scrollList, element) {
+ TableStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(element) {
var tr = document.createElement('tr');
var buffer = document.createElement('td');
- buffer.setAttribute("style", "height: 0px");
+ buffer.setAttribute('style', 'height: 0px');
tr.appendChild(buffer);
element.parentNode.insertBefore(tr, element.nextSibling);
return buffer;
};
- TableStrategy.prototype.removeBufferElements = function removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer.parentElement);
- scrollList.removeChild(bottomBuffer.parentElement);
+ TableStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
};
return TableStrategy;
- })();
+ }());
_export('TableStrategy', TableStrategy);
- DefaultStrategy = (function () {
+ _export('DefaultStrategy', DefaultStrategy = function () {
function DefaultStrategy() {
_classCallCheck(this, DefaultStrategy);
}
- DefaultStrategy.prototype.getScrollList = function getScrollList(element) {
- return element.parentNode;
- };
-
DefaultStrategy.prototype.getScrollContainer = function getScrollContainer(element) {
- return this.getScrollList(element).parentElement;
+ return element.parentNode;
};
- DefaultStrategy.prototype.moveViewFirst = function moveViewFirst(view, scrollElement) {
- insertBeforeNode(view, scrollElement, scrollElement.childNodes[2]);
+ DefaultStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.nextElementSibling.previousSibling);
};
- DefaultStrategy.prototype.moveViewLast = function moveViewLast(view, scrollElement, childrenLength) {
- insertBeforeNode(view, scrollElement, scrollElement.children[childrenLength + 1]);
+ DefaultStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
+ var previousSibling = bottomBuffer.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ insertBeforeNode(view, referenceNode);
};
- DefaultStrategy.prototype.createTopBufferElement = function createTopBufferElement(scrollList, element) {
- var elementName = scrollList.localName === 'ul' ? 'li' : 'div';
+ DefaultStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
+ var elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
var buffer = document.createElement(elementName);
- buffer.setAttribute("style", "height: 0px");
- scrollList.insertBefore(buffer, element);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentElement.insertBefore(buffer, element);
return buffer;
};
- DefaultStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(scrollList, element) {
- var elementName = scrollList.localName === 'ul' ? 'li' : 'div';
+ DefaultStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(element) {
+ var elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
var buffer = document.createElement(elementName);
- buffer.setAttribute("style", "height: 0px");
+ buffer.setAttribute('style', 'height: 0px');
element.parentNode.insertBefore(buffer, element.nextSibling);
return buffer;
};
- DefaultStrategy.prototype.removeBufferElements = function removeBufferElements(scrollList, topBuffer, bottomBuffer) {
- scrollList.removeChild(topBuffer);
- scrollList.removeChild(bottomBuffer);
+ DefaultStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
};
return DefaultStrategy;
- })();
+ }());
_export('DefaultStrategy', DefaultStrategy);
}
diff --git a/dist/system/virtual-list.html b/dist/system/virtual-list.html
deleted file mode 100644
index fcba809..0000000
--- a/dist/system/virtual-list.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
diff --git a/dist/system/virtual-list.js b/dist/system/virtual-list.js
deleted file mode 100644
index 7522f60..0000000
--- a/dist/system/virtual-list.js
+++ /dev/null
@@ -1,43 +0,0 @@
-System.register(['aurelia-templating'], function (_export) {
- 'use strict';
-
- var bindable, VirtualList;
-
- var _createDecoratedClass = (function () { function defineProperties(target, descriptors, initializers) { for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } if (descriptor.initializer !== undefined) { initializers[key] = descriptor; continue; } } Object.defineProperty(target, key, descriptor); } } return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); return Constructor; }; })();
-
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
- function _defineDecoratedPropertyDescriptor(target, key, descriptors) { var _descriptor = descriptors[key]; if (!_descriptor) return; var descriptor = {}; for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; descriptor.value = descriptor.initializer ? descriptor.initializer.call(target) : undefined; Object.defineProperty(target, key, descriptor); }
-
- return {
- setters: [function (_aureliaTemplating) {
- bindable = _aureliaTemplating.bindable;
- }],
- execute: function () {
- VirtualList = (function () {
- var _instanceInitializers = {};
-
- function VirtualList() {
- _classCallCheck(this, VirtualList);
-
- _defineDecoratedPropertyDescriptor(this, 'items', _instanceInitializers);
- }
-
- VirtualList.prototype.bind = function bind(bindingContext, overrideContext) {
- this.$parent = bindingContext;
- };
-
- _createDecoratedClass(VirtualList, [{
- key: 'items',
- decorators: [bindable],
- initializer: null,
- enumerable: true
- }], null, _instanceInitializers);
-
- return VirtualList;
- })();
-
- _export('VirtualList', VirtualList);
- }
- };
-});
\ No newline at end of file
diff --git a/dist/system/virtual-repeat-strategy-locator.js b/dist/system/virtual-repeat-strategy-locator.js
index d703836..4c04ae3 100644
--- a/dist/system/virtual-repeat-strategy-locator.js
+++ b/dist/system/virtual-repeat-strategy-locator.js
@@ -1,36 +1,64 @@
-System.register(['aurelia-templating-resources', './array-virtual-repeat-strategy'], function (_export) {
- 'use strict';
+'use strict';
+System.register(['aurelia-templating-resources/repeat-strategy-locator', './array-virtual-repeat-strategy'], function (_export, _context) {
var RepeatStrategyLocator, ArrayVirtualRepeatStrategy, VirtualRepeatStrategyLocator;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
- function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
return {
- setters: [function (_aureliaTemplatingResources) {
- RepeatStrategyLocator = _aureliaTemplatingResources.RepeatStrategyLocator;
+ setters: [function (_aureliaTemplatingResourcesRepeatStrategyLocator) {
+ RepeatStrategyLocator = _aureliaTemplatingResourcesRepeatStrategyLocator.RepeatStrategyLocator;
}, function (_arrayVirtualRepeatStrategy) {
ArrayVirtualRepeatStrategy = _arrayVirtualRepeatStrategy.ArrayVirtualRepeatStrategy;
}],
execute: function () {
- VirtualRepeatStrategyLocator = (function (_RepeatStrategyLocator) {
- _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocator);
+ _export('VirtualRepeatStrategyLocator', VirtualRepeatStrategyLocator = function (_RepeatStrategyLocato) {
+ _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocato);
function VirtualRepeatStrategyLocator() {
_classCallCheck(this, VirtualRepeatStrategyLocator);
- _RepeatStrategyLocator.call(this);
- this.matchers = [];
- this.strategies = [];
+ var _this = _possibleConstructorReturn(this, _RepeatStrategyLocato.call(this));
+
+ _this.matchers = [];
+ _this.strategies = [];
- this.addStrategy(function (items) {
+ _this.addStrategy(function (items) {
return items instanceof Array;
}, new ArrayVirtualRepeatStrategy());
+ return _this;
}
return VirtualRepeatStrategyLocator;
- })(RepeatStrategyLocator);
+ }(RepeatStrategyLocator));
_export('VirtualRepeatStrategyLocator', VirtualRepeatStrategyLocator);
}
diff --git a/dist/system/virtual-repeat.js b/dist/system/virtual-repeat.js
index 215ac76..66b1a55 100644
--- a/dist/system/virtual-repeat.js
+++ b/dist/system/virtual-repeat.js
@@ -1,22 +1,86 @@
-System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-templating', 'aurelia-templating-resources/repeat-utilities', 'aurelia-templating-resources/analyze-view-factory', './utilities', './virtual-repeat-strategy-locator', './view-strategy'], function (_export) {
- 'use strict';
+'use strict';
+
+System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-templating', 'aurelia-templating-resources', 'aurelia-templating-resources/repeat-utilities', 'aurelia-templating-resources/analyze-view-factory', './utilities', './virtual-repeat-strategy-locator', './view-strategy'], function (_export, _context) {
+ var inject, ObserverLocator, BoundViewFactory, ViewSlot, TargetInstruction, customAttribute, bindable, templateController, AbstractRepeater, getItemsSourceExpression, isOneTime, unwrapExpression, updateOneTimeBinding, viewsRequireLifecycle, getStyleValue, calcOuterHeight, rebindAndMoveView, VirtualRepeatStrategyLocator, ViewStrategyLocator, _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2, VirtualRepeat;
+
+ function _initDefineProp(target, property, descriptor, context) {
+ if (!descriptor) return;
+ Object.defineProperty(target, property, {
+ enumerable: descriptor.enumerable,
+ configurable: descriptor.configurable,
+ writable: descriptor.writable,
+ value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
+ });
+ }
+
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+
+ function _possibleConstructorReturn(self, call) {
+ if (!self) {
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ }
+
+ return call && (typeof call === "object" || typeof call === "function") ? call : self;
+ }
+
+ function _inherits(subClass, superClass) {
+ if (typeof superClass !== "function" && superClass !== null) {
+ throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+ }
+
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
+ constructor: {
+ value: subClass,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+ if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+ }
+
+ function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
+ var desc = {};
+ Object['ke' + 'ys'](descriptor).forEach(function (key) {
+ desc[key] = descriptor[key];
+ });
+ desc.enumerable = !!desc.enumerable;
+ desc.configurable = !!desc.configurable;
+
+ if ('value' in desc || desc.initializer) {
+ desc.writable = true;
+ }
- var inject, ObserverLocator, calcSplices, getChangeRecords, createOverrideContext, BoundViewFactory, ViewSlot, TargetInstruction, customAttribute, bindable, templateController, updateOverrideContext, createFullOverrideContext, updateOverrideContexts, getItemsSourceExpression, isOneTime, unwrapExpression, viewsRequireLifecycle, calcScrollHeight, calcOuterHeight, getNthNode, moveViewFirst, moveViewLast, VirtualRepeatStrategyLocator, ViewStrategyLocator, VirtualRepeat;
+ desc = decorators.slice().reverse().reduce(function (desc, decorator) {
+ return decorator(target, property, desc) || desc;
+ }, desc);
+
+ if (context && desc.initializer !== void 0) {
+ desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
+ desc.initializer = undefined;
+ }
- var _createDecoratedClass = (function () { function defineProperties(target, descriptors, initializers) { for (var i = 0; i < descriptors.length; i++) { var descriptor = descriptors[i]; var decorators = descriptor.decorators; var key = descriptor.key; delete descriptor.key; delete descriptor.decorators; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor || descriptor.initializer) descriptor.writable = true; if (decorators) { for (var f = 0; f < decorators.length; f++) { var decorator = decorators[f]; if (typeof decorator === 'function') { descriptor = decorator(target, key, descriptor) || descriptor; } else { throw new TypeError('The decorator for method ' + descriptor.key + ' is of the invalid type ' + typeof decorator); } } if (descriptor.initializer !== undefined) { initializers[key] = descriptor; continue; } } Object.defineProperty(target, key, descriptor); } } return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); return Constructor; }; })();
+ if (desc.initializer === void 0) {
+ Object['define' + 'Property'](target, property, desc);
+ desc = null;
+ }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+ return desc;
+ }
- function _defineDecoratedPropertyDescriptor(target, key, descriptors) { var _descriptor = descriptors[key]; if (!_descriptor) return; var descriptor = {}; for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; descriptor.value = descriptor.initializer ? descriptor.initializer.call(target) : undefined; Object.defineProperty(target, key, descriptor); }
+ function _initializerWarningHelper(descriptor, context) {
+ throw new Error('Decorating class property failed. Please ensure that transform-class-properties is enabled.');
+ }
return {
setters: [function (_aureliaDependencyInjection) {
inject = _aureliaDependencyInjection.inject;
}, function (_aureliaBinding) {
ObserverLocator = _aureliaBinding.ObserverLocator;
- calcSplices = _aureliaBinding.calcSplices;
- getChangeRecords = _aureliaBinding.getChangeRecords;
- createOverrideContext = _aureliaBinding.createOverrideContext;
}, function (_aureliaTemplating) {
BoundViewFactory = _aureliaTemplating.BoundViewFactory;
ViewSlot = _aureliaTemplating.ViewSlot;
@@ -24,101 +88,93 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
customAttribute = _aureliaTemplating.customAttribute;
bindable = _aureliaTemplating.bindable;
templateController = _aureliaTemplating.templateController;
+ }, function (_aureliaTemplatingResources) {
+ AbstractRepeater = _aureliaTemplatingResources.AbstractRepeater;
}, function (_aureliaTemplatingResourcesRepeatUtilities) {
- updateOverrideContext = _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContext;
- createFullOverrideContext = _aureliaTemplatingResourcesRepeatUtilities.createFullOverrideContext;
- updateOverrideContexts = _aureliaTemplatingResourcesRepeatUtilities.updateOverrideContexts;
getItemsSourceExpression = _aureliaTemplatingResourcesRepeatUtilities.getItemsSourceExpression;
isOneTime = _aureliaTemplatingResourcesRepeatUtilities.isOneTime;
unwrapExpression = _aureliaTemplatingResourcesRepeatUtilities.unwrapExpression;
+ updateOneTimeBinding = _aureliaTemplatingResourcesRepeatUtilities.updateOneTimeBinding;
}, function (_aureliaTemplatingResourcesAnalyzeViewFactory) {
viewsRequireLifecycle = _aureliaTemplatingResourcesAnalyzeViewFactory.viewsRequireLifecycle;
}, function (_utilities) {
- calcScrollHeight = _utilities.calcScrollHeight;
+ getStyleValue = _utilities.getStyleValue;
calcOuterHeight = _utilities.calcOuterHeight;
- getNthNode = _utilities.getNthNode;
- moveViewFirst = _utilities.moveViewFirst;
- moveViewLast = _utilities.moveViewLast;
+ rebindAndMoveView = _utilities.rebindAndMoveView;
}, function (_virtualRepeatStrategyLocator) {
VirtualRepeatStrategyLocator = _virtualRepeatStrategyLocator.VirtualRepeatStrategyLocator;
}, function (_viewStrategy) {
ViewStrategyLocator = _viewStrategy.ViewStrategyLocator;
}],
execute: function () {
- VirtualRepeat = (function () {
- var _instanceInitializers = {};
-
- _createDecoratedClass(VirtualRepeat, [{
- key: 'items',
- decorators: [bindable],
- initializer: null,
- enumerable: true
- }, {
- key: 'local',
- decorators: [bindable],
- initializer: null,
- enumerable: true
- }], null, _instanceInitializers);
+ _export('VirtualRepeat', VirtualRepeat = (_dec = customAttribute('virtual-repeat'), _dec2 = inject(Element, BoundViewFactory, TargetInstruction, ViewSlot, ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator), _dec(_class = templateController(_class = _dec2(_class = (_class2 = function (_AbstractRepeater) {
+ _inherits(VirtualRepeat, _AbstractRepeater);
function VirtualRepeat(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
- _classCallCheck(this, _VirtualRepeat);
-
- this._first = 0;
- this._previousFirst = 0;
- this._viewsLength = 0;
- this._lastRebind = 0;
- this._topBufferHeight = 0;
- this._bottomBufferHeight = 0;
- this._bufferSize = 5;
- this._scrollingDown = false;
- this._scrollingUp = false;
- this._switchedDirection = false;
- this._isAttached = false;
- this._ticking = false;
-
- _defineDecoratedPropertyDescriptor(this, 'items', _instanceInitializers);
-
- _defineDecoratedPropertyDescriptor(this, 'local', _instanceInitializers);
-
- this.element = element;
- this.viewFactory = viewFactory;
- this.instruction = instruction;
- this.viewSlot = viewSlot;
- this.observerLocator = observerLocator;
- this.strategyLocator = strategyLocator;
- this.viewStrategyLocator = viewStrategyLocator;
- this.local = 'item';
- this.sourceExpression = getItemsSourceExpression(this.instruction, 'virtual-repeat.for');
- this.isOneTime = isOneTime(this.sourceExpression);
- this.viewsRequireLifecycle = viewsRequireLifecycle(viewFactory);
+ _classCallCheck(this, VirtualRepeat);
+
+ var _this = _possibleConstructorReturn(this, _AbstractRepeater.call(this, {
+ local: 'item',
+ viewsRequireLifecycle: viewsRequireLifecycle(viewFactory)
+ }));
+
+ _this._first = 0;
+ _this._previousFirst = 0;
+ _this._viewsLength = 0;
+ _this._lastRebind = 0;
+ _this._topBufferHeight = 0;
+ _this._bottomBufferHeight = 0;
+ _this._bufferSize = 5;
+ _this._scrollingDown = false;
+ _this._scrollingUp = false;
+ _this._switchedDirection = false;
+ _this._isAttached = false;
+ _this._ticking = false;
+ _this._fixedHeightContainer = false;
+ _this._hasCalculatedSizes = false;
+ _this._isAtTop = true;
+
+ _initDefineProp(_this, 'items', _descriptor, _this);
+
+ _initDefineProp(_this, 'local', _descriptor2, _this);
+
+ _this.element = element;
+ _this.viewFactory = viewFactory;
+ _this.instruction = instruction;
+ _this.viewSlot = viewSlot;
+ _this.observerLocator = observerLocator;
+ _this.strategyLocator = strategyLocator;
+ _this.viewStrategyLocator = viewStrategyLocator;
+ _this.sourceExpression = getItemsSourceExpression(_this.instruction, 'virtual-repeat.for');
+ _this.isOneTime = isOneTime(_this.sourceExpression);
+ return _this;
}
VirtualRepeat.prototype.attached = function attached() {
- var _this = this;
+ var _this2 = this;
this._isAttached = true;
var element = this.element;
this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
- this.scrollList = this.viewStrategy.getScrollList(element);
this.scrollContainer = this.viewStrategy.getScrollContainer(element);
- this.topBuffer = this.viewStrategy.createTopBufferElement(this.scrollList, element);
- this.bottomBuffer = this.viewStrategy.createBottomBufferElement(this.scrollList, element);
+ this.topBuffer = this.viewStrategy.createTopBufferElement(element);
+ this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
this.itemsChanged();
this.scrollListener = function () {
- return _this._onScroll();
+ return _this2._onScroll();
};
- this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ var containerStyle = this.scrollContainer.style;
+ if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
+ this._fixedHeightContainer = true;
+ this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ } else {
+ document.addEventListener('scroll', this.scrollListener);
+ }
};
VirtualRepeat.prototype.bind = function bind(bindingContext, overrideContext) {
- var _this2 = this;
-
this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
this._itemsLength = this.items.length;
-
- window.onresize = function () {
- _this2._handleResize();
- };
};
VirtualRepeat.prototype.call = function call(context, changes) {
@@ -138,12 +194,12 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
this._switchedDirection = false;
this._isAttached = false;
this._ticking = false;
- this.viewStrategy.removeBufferElements(this.scrollList, this.topBuffer, this.bottomBuffer);
+ this._hasCalculatedSizes = false;
+ this.viewStrategy.removeBufferElements(this.element, this.topBuffer, this.bottomBuffer);
this.isLastIndex = false;
- this.scrollList = null;
this.scrollContainer = null;
this.scrollContainerHeight = null;
- this.viewSlot.removeAll(true);
+ this.removeAllViews(true);
if (this.scrollHandler) {
this.scrollHandler.dispose();
}
@@ -158,8 +214,10 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
}
var items = this.items;
this.strategy = this.strategyLocator.getStrategy(items);
- this.strategy.createFirstItem(this);
- this._calcInitialHeights();
+ if (items.length > 0) {
+ this.strategy.createFirstItem(this);
+ }
+ this._calcInitialHeights(items.length);
if (!this.isOneTime && !this._observeInnerCollection()) {
this._observeCollection();
}
@@ -174,6 +232,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
};
VirtualRepeat.prototype.handleCollectionMutated = function handleCollectionMutated(collection, changes) {
+ this._handlingMutations = true;
this._itemsLength = collection.length;
this.strategy.instanceMutated(this, collection, changes);
};
@@ -200,12 +259,16 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
VirtualRepeat.prototype._onScroll = function _onScroll() {
var _this4 = this;
- if (!this._ticking) {
+ if (!this._ticking && !this._handlingMutations) {
requestAnimationFrame(function () {
return _this4._handleScroll();
});
this._ticking = true;
}
+
+ if (this._handlingMutations) {
+ this._handlingMutations = false;
+ }
};
VirtualRepeat.prototype._handleScroll = function _handleScroll() {
@@ -213,73 +276,55 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
return;
}
var itemHeight = this.itemHeight;
- var scrollTop = this.scrollContainer.scrollTop;
+ var scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
this._first = Math.floor(scrollTop / itemHeight);
+ this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
this._checkScrolling();
- if (this._scrollingDown && (this._hasScrolledDownTheBuffer() || this._switchedDirection && this._hasScrolledDownTheBufferFromTop())) {
+ if (this._scrollingDown) {
var viewsToMove = this._first - this._lastRebind;
if (this._switchedDirection) {
- viewsToMove = this.isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
}
- this.isAtTop = false;
+ this._isAtTop = false;
this._lastRebind = this._first;
var movedViewsCount = this._moveViews(viewsToMove);
var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
- var test = 0;
this._switchedDirection = false;
this._topBufferHeight = this._topBufferHeight + adjustHeight;
this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
if (this._bottomBufferHeight >= 0) {
this._adjustBufferHeights();
}
- } else if (this._scrollingUp && (this._hasScrolledUpTheBuffer() || this._switchedDirection && this._hasScrolledUpTheBufferFromBottom())) {
- var viewsToMove = this._lastRebind - this._first;
- if (this._switchedDirection) {
- if (this.isLastIndex) {
- viewsToMove = this.items.length - this._first - this.elementsInView;
- } else {
- viewsToMove = this._bufferSize - (this._first - this._lastRebind);
- }
- }
- this.isLastIndex = false;
- this._lastRebind = this._first;
- var movedViewsCount = this._moveViews(viewsToMove);
- this.movedViewsCount = movedViewsCount;
- var adjustHeight = movedViewsCount < viewsToMove ? this._topBufferHeight : itemHeight * movedViewsCount;
- this._switchedDirection = false;
- this._topBufferHeight = this._topBufferHeight - adjustHeight;
- this._bottomBufferHeight = this._bottomBufferHeight + adjustHeight;
- if (this._topBufferHeight >= 0) {
- this._adjustBufferHeights();
+ } else if (this._scrollingUp) {
+ var _viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ _viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ _viewsToMove = this._bufferSize - (this._first - this._lastRebind);
}
}
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ var _movedViewsCount = this._moveViews(_viewsToMove);
+ this.movedViewsCount = _movedViewsCount;
+ var _adjustHeight = _movedViewsCount < _viewsToMove ? this._topBufferHeight : itemHeight * _movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - _adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + _adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
this._previousFirst = this._first;
this._ticking = false;
};
- VirtualRepeat.prototype._handleResize = function _handleResize() {
- var children = this.viewSlot.children,
- childrenLength = children.length,
- overrideContext,
- view,
- addIndex;
-
- this.scrollContainerHeight = calcScrollHeight(this.scrollContainer);
- this._viewsLength = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
-
- if (this._viewsLength > childrenLength) {
- addIndex = children[childrenLength - 1].overrideContext.$index + 1;
- overrideContext = createFullOverrideContext(this, this.items[addIndex], addIndex, this.items.length);
- view = this.viewFactory.create();
- view.bind(overrideContext.bindingContext, overrideContext);
- this.viewSlot.insert(childrenLength, view);
- } else if (this._viewsLength < childrenLength) {
- this._viewsLength = childrenLength;
- }
- };
-
VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
if (!this._scrollingDown) {
@@ -290,7 +335,7 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
this._switchedDirection = false;
}
this._isScrolling = true;
- } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this.isAtTop)) {
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
if (!this._scrollingUp) {
this._scrollingDown = false;
this._scrollingUp = true;
@@ -304,27 +349,9 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
}
};
- VirtualRepeat.prototype._hasScrolledDownTheBuffer = function _hasScrolledDownTheBuffer() {
- var atBottom = this._first + this._viewsLength >= this.items.length;
- var itemsAddedWhileAtBottom = atBottom && this._first > this._lastRebind;
- return this._first - this._lastRebind >= this._bufferSize || itemsAddedWhileAtBottom;
- };
-
- VirtualRepeat.prototype._hasScrolledDownTheBufferFromTop = function _hasScrolledDownTheBufferFromTop() {
- return this._first - this._bufferSize > 0;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBuffer = function _hasScrolledUpTheBuffer() {
- return this._lastRebind - this._first >= this._bufferSize;
- };
-
- VirtualRepeat.prototype._hasScrolledUpTheBufferFromBottom = function _hasScrolledUpTheBufferFromBottom() {
- return this._first + this._bufferSize < this.items.length;
- };
-
VirtualRepeat.prototype._adjustBufferHeights = function _adjustBufferHeights() {
this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
- this.bottomBuffer.setAttribute("style", 'height: ' + this._bottomBufferHeight + 'px');
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
};
VirtualRepeat.prototype._unsubscribeCollection = function _unsubscribeCollection() {
@@ -344,63 +371,69 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
return index - i;
};
var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
- return _this5._scrollingDown ? _this5.isLastIndex : _this5.isAtTop;
+ return _this5._scrollingDown ? _this5.isLastIndex : _this5._isAtTop;
};
- var viewSlot = this.viewSlot;
- var childrenLength = viewSlot.children.length;
+ var childrenLength = this.viewCount();
var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
var items = this.items;
- var scrollList = this.scrollList;
var index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
var i = 0;
while (i < length && !isAtFirstOrLastIndex()) {
- var view = viewSlot.children[viewIndex];
+ var view = this.view(viewIndex);
var nextIndex = getNextIndex(index, i);
- updateOverrideContext(view.overrideContext, nextIndex, items.length);
- view.bindingContext[this.local] = items[nextIndex];
- if (this._scrollingDown) {
- viewSlot.children.push(viewSlot.children.shift());
- this.viewStrategy.moveViewLast(view, scrollList, childrenLength);
- this.isLastIndex = nextIndex >= items.length - 1;
- } else {
- viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
- this.viewStrategy.moveViewFirst(view, scrollList);
- this.isAtTop = nextIndex <= 0;
+ this.isLastIndex = nextIndex >= items.length - 1;
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
+ rebindAndMoveView(this, view, nextIndex, this._scrollingDown);
+ i++;
}
- i++;
}
+
return length - (length - i);
};
VirtualRepeat.prototype._getIndexOfLastView = function _getIndexOfLastView() {
- var children = this.viewSlot.children;
- return children[children.length - 1].overrideContext.$index;
+ return this.view(this.viewCount() - 1).overrideContext.$index;
};
VirtualRepeat.prototype._getIndexOfFirstView = function _getIndexOfFirstView() {
- var children = this.viewSlot.children;
- return children[0].overrideContext.$index;
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
};
- VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights() {
- if (this._viewsLength > 0 && this._itemsLength == this.items.length) {
+ VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights(itemsLength) {
+ if (this._viewsLength > 0 && this._itemsLength === itemsLength || itemsLength <= 0) {
return;
}
- this._itemsLength = this.items.length;
- var listItems = this.scrollList.children;
- this.itemHeight = calcOuterHeight(listItems[1]);
- this.scrollContainerHeight = calcScrollHeight(this.scrollContainer);
+ this._hasCalculatedSizes = true;
+ this._itemsLength = itemsLength;
+ var firstViewElement = this.view(0).firstChild.nextElementSibling;
+ this.itemHeight = calcOuterHeight(firstViewElement);
+ if (this.itemHeight <= 0) {
+ throw new Error('Could not calculate item height');
+ }
+ this.scrollContainerHeight = this._fixedHeightContainer ? this._calcScrollHeight(this.scrollContainer) : document.documentElement.clientHeight;
this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
this._viewsLength = this.elementsInView * 2 + this._bufferSize;
- this._bottomBufferHeight = this.itemHeight * this.items.length - this.itemHeight * this._viewsLength;
- this.bottomBuffer.setAttribute("style", 'height: ' + this._bottomBufferHeight + 'px');
+ this._bottomBufferHeight = this.itemHeight * itemsLength - this.itemHeight * this._viewsLength;
+ if (this._bottomBufferHeight < 0) {
+ this._bottomBufferHeight = 0;
+ }
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
this._topBufferHeight = 0;
- this.topBuffer.setAttribute("style", 'height: ' + this._topBufferHeight + 'px');
+ this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
this.scrollContainer.scrollTop = 0;
this._first = 0;
};
+ VirtualRepeat.prototype._calcScrollHeight = function _calcScrollHeight(element) {
+ var height = void 0;
+ height = element.getBoundingClientRect().height;
+ height -= getStyleValue(element, 'borderTopWidth');
+ height -= getStyleValue(element, 'borderBottomWidth');
+ return height;
+ };
+
VirtualRepeat.prototype._observeInnerCollection = function _observeInnerCollection() {
var items = this._getInnerCollection();
var strategy = this.strategyLocator.getStrategy(items);
@@ -433,12 +466,61 @@ System.register(['aurelia-dependency-injection', 'aurelia-binding', 'aurelia-tem
}
};
- var _VirtualRepeat = VirtualRepeat;
- VirtualRepeat = inject(Element, BoundViewFactory, TargetInstruction, ViewSlot, ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator)(VirtualRepeat) || VirtualRepeat;
- VirtualRepeat = templateController(VirtualRepeat) || VirtualRepeat;
- VirtualRepeat = customAttribute('virtual-repeat')(VirtualRepeat) || VirtualRepeat;
+ VirtualRepeat.prototype.viewCount = function viewCount() {
+ return this.viewSlot.children.length;
+ };
+
+ VirtualRepeat.prototype.views = function views() {
+ return this.viewSlot.children;
+ };
+
+ VirtualRepeat.prototype.view = function view(index) {
+ return this.viewSlot.children[index];
+ };
+
+ VirtualRepeat.prototype.addView = function addView(bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ };
+
+ VirtualRepeat.prototype.insertView = function insertView(index, bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ };
+
+ VirtualRepeat.prototype.removeAllViews = function removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.removeView = function removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.updateBindings = function updateBindings(view) {
+ var j = view.bindings.length;
+ while (j--) {
+ updateOneTimeBinding(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ var k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ var binding = view.controllers[j].boundProperties[k].binding;
+ updateOneTimeBinding(binding);
+ }
+ }
+ };
+
return VirtualRepeat;
- })();
+ }(AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [bindable], {
+ enumerable: true,
+ initializer: null
+ }), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, 'local', [bindable], {
+ enumerable: true,
+ initializer: null
+ })), _class2)) || _class) || _class) || _class));
_export('VirtualRepeat', VirtualRepeat);
}
diff --git a/dist/temp/aurelia-ui-virtualization.js b/dist/temp/aurelia-ui-virtualization.js
new file mode 100644
index 0000000..5d79c69
--- /dev/null
+++ b/dist/temp/aurelia-ui-virtualization.js
@@ -0,0 +1,916 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.VirtualRepeat = exports.VirtualRepeatStrategyLocator = exports.DefaultStrategy = exports.TableStrategy = exports.ViewStrategyLocator = exports.ArrayVirtualRepeatStrategy = undefined;
+
+var _dec, _dec2, _class, _desc, _value, _class2, _descriptor, _descriptor2;
+
+exports.calcOuterHeight = calcOuterHeight;
+exports.insertBeforeNode = insertBeforeNode;
+exports.updateVirtualOverrideContexts = updateVirtualOverrideContexts;
+exports.rebindAndMoveView = rebindAndMoveView;
+exports.getStyleValue = getStyleValue;
+exports.getElementDistanceToBottomViewPort = getElementDistanceToBottomViewPort;
+
+var _repeatUtilities = require('aurelia-templating-resources/repeat-utilities');
+
+var _arrayRepeatStrategy = require('aurelia-templating-resources/array-repeat-strategy');
+
+var _repeatStrategyLocator = require('aurelia-templating-resources/repeat-strategy-locator');
+
+var _aureliaDependencyInjection = require('aurelia-dependency-injection');
+
+var _aureliaBinding = require('aurelia-binding');
+
+var _aureliaTemplating = require('aurelia-templating');
+
+var _aureliaTemplatingResources = require('aurelia-templating-resources');
+
+var _analyzeViewFactory = require('aurelia-templating-resources/analyze-view-factory');
+
+function _initDefineProp(target, property, descriptor, context) {
+ if (!descriptor) return;
+ Object.defineProperty(target, property, {
+ enumerable: descriptor.enumerable,
+ configurable: descriptor.configurable,
+ writable: descriptor.writable,
+ value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
+ });
+}
+
+function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
+ var desc = {};
+ Object['ke' + 'ys'](descriptor).forEach(function (key) {
+ desc[key] = descriptor[key];
+ });
+ desc.enumerable = !!desc.enumerable;
+ desc.configurable = !!desc.configurable;
+
+ if ('value' in desc || desc.initializer) {
+ desc.writable = true;
+ }
+
+ desc = decorators.slice().reverse().reduce(function (desc, decorator) {
+ return decorator(target, property, desc) || desc;
+ }, desc);
+
+ if (context && desc.initializer !== void 0) {
+ desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
+ desc.initializer = undefined;
+ }
+
+ if (desc.initializer === void 0) {
+ Object['define' + 'Property'](target, property, desc);
+ desc = null;
+ }
+
+ return desc;
+}
+
+function _initializerWarningHelper(descriptor, context) {
+ throw new Error('Decorating class property failed. Please ensure that transform-class-properties is enabled.');
+}
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+function calcOuterHeight(element) {
+ var height = void 0;
+ height = element.getBoundingClientRect().height;
+ height += getStyleValue(element, 'marginTop');
+ height += getStyleValue(element, 'marginBottom');
+ return height;
+}
+
+function insertBeforeNode(view, bottomBuffer) {
+ var viewStart = view.firstChild;
+ var element = viewStart.nextSibling;
+ var viewEnd = view.lastChild;
+ var parentElement = bottomBuffer.parentElement;
+
+ parentElement.insertBefore(viewEnd, bottomBuffer);
+ parentElement.insertBefore(element, viewEnd);
+ parentElement.insertBefore(viewStart, element);
+}
+
+function updateVirtualOverrideContexts(repeat, startIndex) {
+ var views = repeat.viewSlot.children;
+ var viewLength = views.length;
+ var collectionLength = repeat.items.length;
+
+ if (startIndex > 0) {
+ startIndex = startIndex - 1;
+ }
+
+ var delta = repeat._topBufferHeight / repeat.itemHeight;
+
+ for (; startIndex < viewLength; ++startIndex) {
+ (0, _repeatUtilities.updateOverrideContext)(views[startIndex].overrideContext, startIndex + delta, collectionLength);
+ }
+}
+
+function rebindAndMoveView(repeat, view, index, moveToBottom) {
+ var items = repeat.items;
+ var viewSlot = repeat.viewSlot;
+ (0, _repeatUtilities.updateOverrideContext)(view.overrideContext, index, items.length);
+ view.bindingContext[repeat.local] = items[index];
+ if (moveToBottom) {
+ viewSlot.children.push(viewSlot.children.shift());
+ repeat.viewStrategy.moveViewLast(view, repeat.bottomBuffer);
+ } else {
+ viewSlot.children.unshift(viewSlot.children.splice(-1, 1)[0]);
+ repeat.viewStrategy.moveViewFirst(view, repeat.topBuffer);
+ }
+}
+
+function getStyleValue(element, style) {
+ var currentStyle = void 0;
+ var styleValue = void 0;
+ currentStyle = element.currentStyle || window.getComputedStyle(element);
+ styleValue = parseInt(currentStyle[style], 10);
+ return Number.isNaN(styleValue) ? 0 : styleValue;
+}
+
+function getElementDistanceToBottomViewPort(element) {
+ return document.documentElement.clientHeight - element.getBoundingClientRect().bottom;
+}
+
+var ArrayVirtualRepeatStrategy = exports.ArrayVirtualRepeatStrategy = function (_ArrayRepeatStrategy) {
+ _inherits(ArrayVirtualRepeatStrategy, _ArrayRepeatStrategy);
+
+ function ArrayVirtualRepeatStrategy() {
+ _classCallCheck(this, ArrayVirtualRepeatStrategy);
+
+ return _possibleConstructorReturn(this, _ArrayRepeatStrategy.apply(this, arguments));
+ }
+
+ ArrayVirtualRepeatStrategy.prototype.createFirstItem = function createFirstItem(repeat) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[0], 0, 1);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ };
+
+ ArrayVirtualRepeatStrategy.prototype.instanceChanged = function instanceChanged(repeat, items) {
+ this._inPlaceProcessItems(repeat, items);
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceChanged = function _standardProcessInstanceChanged(repeat, items) {
+ for (var i = 1, ii = repeat._viewsLength; i < ii; ++i) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[i], i, ii);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._inPlaceProcessItems = function _inPlaceProcessItems(repeat, items) {
+ var itemsLength = items.length;
+ var viewsLength = repeat.viewCount();
+ var first = repeat._getIndexOfFirstView();
+
+ while (viewsLength > repeat._viewsLength) {
+ viewsLength--;
+ repeat.removeView(viewsLength, true);
+ }
+
+ var local = repeat.local;
+
+ for (var i = 0; i < viewsLength; i++) {
+ var view = repeat.view(i);
+ var last = i === itemsLength - 1;
+ var middle = i !== 0 && !last;
+
+ if (view.bindingContext[local] === items[i + first] && view.overrideContext.$middle === middle && view.overrideContext.$last === last) {
+ continue;
+ }
+
+ view.bindingContext[local] = items[i + first];
+ view.overrideContext.$middle = middle;
+ view.overrideContext.$last = last;
+ repeat.updateBindings(view);
+ }
+
+ var minLength = Math.min(repeat._viewsLength, items.length);
+ for (var _i = viewsLength; _i < minLength; _i++) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, items[_i], _i, itemsLength);
+ repeat.addView(overrideContext.bindingContext, overrideContext);
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype.instanceMutated = function instanceMutated(repeat, array, splices) {
+ this._standardProcessInstanceMutated(repeat, array, splices);
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._standardProcessInstanceMutated = function _standardProcessInstanceMutated(repeat, array, splices) {
+ var _this2 = this;
+
+ if (repeat.__queuedSplices) {
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var _splices$i = splices[i];
+ var index = _splices$i.index;
+ var removed = _splices$i.removed;
+ var addedCount = _splices$i.addedCount;
+
+ mergeSplice(repeat.__queuedSplices, index, removed, addedCount);
+ }
+ repeat.__array = array.slice(0);
+ return;
+ }
+
+ var maybePromise = this._runSplices(repeat, array.slice(0), splices);
+ if (maybePromise instanceof Promise) {
+ (function () {
+ var queuedSplices = repeat.__queuedSplices = [];
+
+ var runQueuedSplices = function runQueuedSplices() {
+ if (!queuedSplices.length) {
+ delete repeat.__queuedSplices;
+ delete repeat.__array;
+ return;
+ }
+
+ var nextPromise = _this2._runSplices(repeat, repeat.__array, queuedSplices) || Promise.resolve();
+ nextPromise.then(runQueuedSplices);
+ };
+
+ maybePromise.then(runQueuedSplices);
+ })();
+ }
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._runSplices = function _runSplices(repeat, array, splices) {
+ var _this3 = this;
+
+ var removeDelta = 0;
+ var rmPromises = [];
+
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var splice = splices[i];
+ var removed = splice.removed;
+ for (var j = 0, jj = removed.length; j < jj; ++j) {
+ var viewOrPromise = this._removeViewAt(repeat, splice.index + removeDelta + rmPromises.length, true);
+ if (viewOrPromise instanceof Promise) {
+ rmPromises.push(viewOrPromise);
+ }
+ }
+ removeDelta -= splice.addedCount;
+ }
+
+ if (rmPromises.length > 0) {
+ return Promise.all(rmPromises).then(function () {
+ _this3._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ });
+ }
+ this._handleAddedSplices(repeat, array, splices);
+ updateVirtualOverrideContexts(repeat, 0);
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._removeViewAt = function _removeViewAt(repeat, collectionIndex, returnToCache) {
+ var viewOrPromise = void 0;
+ var view = void 0;
+ var viewSlot = repeat.viewSlot;
+ var viewCount = repeat.viewCount();
+ var viewAddIndex = void 0;
+
+ if (!this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, collectionIndex);
+ viewOrPromise = repeat.removeView(viewIndex, returnToCache);
+ if (repeat.items.length > viewCount) {
+ var collectionAddIndex = void 0;
+ if (repeat._bottomBufferHeight > repeat.itemHeight) {
+ viewAddIndex = viewCount;
+ collectionAddIndex = repeat._getIndexOfLastView() + 1;
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ } else if (repeat._topBufferHeight > 0) {
+ viewAddIndex = 0;
+ collectionAddIndex = repeat._getIndexOfFirstView() - 1;
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ var data = repeat.items[collectionAddIndex];
+ if (data) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, repeat.items[collectionAddIndex], collectionAddIndex, repeat.items.length);
+ view = repeat.viewFactory.create();
+ view.bind(overrideContext.bindingContext, overrideContext);
+ }
+ } else {
+ return viewOrPromise;
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, collectionIndex)) {
+ if (repeat._bottomBufferHeight > 0) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ rebindAndMoveView(repeat, repeat.view(0), repeat.view(0).overrideContext.$index, true);
+ } else {
+ repeat._topBufferHeight = repeat._topBufferHeight - repeat.itemHeight;
+ }
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, collectionIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight - repeat.itemHeight;
+ }
+
+ if (viewOrPromise instanceof Promise) {
+ viewOrPromise.then(function () {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ repeat._adjustBufferHeights();
+ });
+ return undefined;
+ } else if (view) {
+ repeat.viewSlot.insert(viewAddIndex, view);
+ }
+
+ repeat._adjustBufferHeights();
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._isIndexBeforeViewSlot = function _isIndexBeforeViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex < 0;
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._isIndexAfterViewSlot = function _isIndexAfterViewSlot(repeat, viewSlot, index) {
+ var viewIndex = this._getViewIndex(repeat, viewSlot, index);
+ return viewIndex > repeat._viewsLength - 1;
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._getViewIndex = function _getViewIndex(repeat, viewSlot, index) {
+ if (repeat.viewCount() === 0) {
+ return -1;
+ }
+
+ var topBufferItems = repeat._topBufferHeight / repeat.itemHeight;
+ return index - topBufferItems;
+ };
+
+ ArrayVirtualRepeatStrategy.prototype._handleAddedSplices = function _handleAddedSplices(repeat, array, splices) {
+ var arrayLength = array.length;
+ var viewSlot = repeat.viewSlot;
+ for (var i = 0, ii = splices.length; i < ii; ++i) {
+ var splice = splices[i];
+ var addIndex = splice.index;
+ var end = splice.index + splice.addedCount;
+ for (; addIndex < end; ++addIndex) {
+ var hasDistanceToBottomViewPort = getElementDistanceToBottomViewPort(repeat.bottomBuffer.previousElementSibling) > 0;
+ if (repeat.viewCount() === 0 || !this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex) && !this._isIndexAfterViewSlot(repeat, viewSlot, addIndex) || hasDistanceToBottomViewPort) {
+ var overrideContext = (0, _repeatUtilities.createFullOverrideContext)(repeat, array[addIndex], addIndex, arrayLength);
+ repeat.insertView(addIndex, overrideContext.bindingContext, overrideContext);
+ if (!repeat._hasCalculatedSizes) {
+ repeat._calcInitialHeights(1);
+ } else if (repeat.viewCount() > repeat._viewsLength) {
+ if (hasDistanceToBottomViewPort) {
+ repeat.removeView(0, true, true);
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ repeat._adjustBufferHeights();
+ } else {
+ repeat.removeView(repeat.viewCount() - 1, true, true);
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ }
+ }
+ } else if (this._isIndexBeforeViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._topBufferHeight = repeat._topBufferHeight + repeat.itemHeight;
+ } else if (this._isIndexAfterViewSlot(repeat, viewSlot, addIndex)) {
+ repeat._bottomBufferHeight = repeat._bottomBufferHeight + repeat.itemHeight;
+ repeat.isLastIndex = false;
+ }
+ }
+ }
+ repeat._adjustBufferHeights();
+ };
+
+ return ArrayVirtualRepeatStrategy;
+}(_arrayRepeatStrategy.ArrayRepeatStrategy);
+
+var ViewStrategyLocator = exports.ViewStrategyLocator = function () {
+ function ViewStrategyLocator() {
+ _classCallCheck(this, ViewStrategyLocator);
+ }
+
+ ViewStrategyLocator.prototype.getStrategy = function getStrategy(element) {
+ if (element.parentNode.localName === 'tbody') {
+ return new TableStrategy();
+ }
+ return new DefaultStrategy();
+ };
+
+ return ViewStrategyLocator;
+}();
+
+var TableStrategy = exports.TableStrategy = function () {
+ function TableStrategy() {
+ _classCallCheck(this, TableStrategy);
+ }
+
+ TableStrategy.prototype.getScrollContainer = function getScrollContainer(element) {
+ return element.parentNode;
+ };
+
+ TableStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.parentElement.nextElementSibling.previousSibling);
+ };
+
+ TableStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
+ insertBeforeNode(view, bottomBuffer.parentElement);
+ };
+
+ TableStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
+ var tr = document.createElement('tr');
+ var buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentElement.insertBefore(tr, element);
+ return buffer;
+ };
+
+ TableStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(element) {
+ var tr = document.createElement('tr');
+ var buffer = document.createElement('td');
+ buffer.setAttribute('style', 'height: 0px');
+ tr.appendChild(buffer);
+ element.parentNode.insertBefore(tr, element.nextSibling);
+ return buffer;
+ };
+
+ TableStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer.parentElement);
+ element.parentElement.removeChild(bottomBuffer.parentElement);
+ };
+
+ return TableStrategy;
+}();
+
+var DefaultStrategy = exports.DefaultStrategy = function () {
+ function DefaultStrategy() {
+ _classCallCheck(this, DefaultStrategy);
+ }
+
+ DefaultStrategy.prototype.getScrollContainer = function getScrollContainer(element) {
+ return element.parentNode;
+ };
+
+ DefaultStrategy.prototype.moveViewFirst = function moveViewFirst(view, topBuffer) {
+ insertBeforeNode(view, topBuffer.nextElementSibling.previousSibling);
+ };
+
+ DefaultStrategy.prototype.moveViewLast = function moveViewLast(view, bottomBuffer) {
+ var previousSibling = bottomBuffer.previousSibling;
+ var referenceNode = previousSibling.nodeType === 8 && previousSibling.data === 'anchor' ? previousSibling : bottomBuffer;
+ insertBeforeNode(view, referenceNode);
+ };
+
+ DefaultStrategy.prototype.createTopBufferElement = function createTopBufferElement(element) {
+ var elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ var buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentElement.insertBefore(buffer, element);
+ return buffer;
+ };
+
+ DefaultStrategy.prototype.createBottomBufferElement = function createBottomBufferElement(element) {
+ var elementName = element.parentElement.localName === 'ul' ? 'li' : 'div';
+ var buffer = document.createElement(elementName);
+ buffer.setAttribute('style', 'height: 0px');
+ element.parentNode.insertBefore(buffer, element.nextSibling);
+ return buffer;
+ };
+
+ DefaultStrategy.prototype.removeBufferElements = function removeBufferElements(element, topBuffer, bottomBuffer) {
+ element.parentElement.removeChild(topBuffer);
+ element.parentElement.removeChild(bottomBuffer);
+ };
+
+ return DefaultStrategy;
+}();
+
+var VirtualRepeatStrategyLocator = exports.VirtualRepeatStrategyLocator = function (_RepeatStrategyLocato) {
+ _inherits(VirtualRepeatStrategyLocator, _RepeatStrategyLocato);
+
+ function VirtualRepeatStrategyLocator() {
+ _classCallCheck(this, VirtualRepeatStrategyLocator);
+
+ var _this4 = _possibleConstructorReturn(this, _RepeatStrategyLocato.call(this));
+
+ _this4.matchers = [];
+ _this4.strategies = [];
+
+ _this4.addStrategy(function (items) {
+ return items instanceof Array;
+ }, new ArrayVirtualRepeatStrategy());
+ return _this4;
+ }
+
+ return VirtualRepeatStrategyLocator;
+}(_repeatStrategyLocator.RepeatStrategyLocator);
+
+var VirtualRepeat = exports.VirtualRepeat = (_dec = (0, _aureliaTemplating.customAttribute)('virtual-repeat'), _dec2 = (0, _aureliaDependencyInjection.inject)(Element, _aureliaTemplating.BoundViewFactory, _aureliaTemplating.TargetInstruction, _aureliaTemplating.ViewSlot, _aureliaBinding.ObserverLocator, VirtualRepeatStrategyLocator, ViewStrategyLocator), _dec(_class = (0, _aureliaTemplating.templateController)(_class = _dec2(_class = (_class2 = function (_AbstractRepeater) {
+ _inherits(VirtualRepeat, _AbstractRepeater);
+
+ function VirtualRepeat(element, viewFactory, instruction, viewSlot, observerLocator, strategyLocator, viewStrategyLocator) {
+ _classCallCheck(this, VirtualRepeat);
+
+ var _this5 = _possibleConstructorReturn(this, _AbstractRepeater.call(this, {
+ local: 'item',
+ viewsRequireLifecycle: (0, _analyzeViewFactory.viewsRequireLifecycle)(viewFactory)
+ }));
+
+ _this5._first = 0;
+ _this5._previousFirst = 0;
+ _this5._viewsLength = 0;
+ _this5._lastRebind = 0;
+ _this5._topBufferHeight = 0;
+ _this5._bottomBufferHeight = 0;
+ _this5._bufferSize = 5;
+ _this5._scrollingDown = false;
+ _this5._scrollingUp = false;
+ _this5._switchedDirection = false;
+ _this5._isAttached = false;
+ _this5._ticking = false;
+ _this5._fixedHeightContainer = false;
+ _this5._hasCalculatedSizes = false;
+ _this5._isAtTop = true;
+
+ _initDefineProp(_this5, 'items', _descriptor, _this5);
+
+ _initDefineProp(_this5, 'local', _descriptor2, _this5);
+
+ _this5.element = element;
+ _this5.viewFactory = viewFactory;
+ _this5.instruction = instruction;
+ _this5.viewSlot = viewSlot;
+ _this5.observerLocator = observerLocator;
+ _this5.strategyLocator = strategyLocator;
+ _this5.viewStrategyLocator = viewStrategyLocator;
+ _this5.sourceExpression = (0, _repeatUtilities.getItemsSourceExpression)(_this5.instruction, 'virtual-repeat.for');
+ _this5.isOneTime = (0, _repeatUtilities.isOneTime)(_this5.sourceExpression);
+ return _this5;
+ }
+
+ VirtualRepeat.prototype.attached = function attached() {
+ var _this6 = this;
+
+ this._isAttached = true;
+ var element = this.element;
+ this.viewStrategy = this.viewStrategyLocator.getStrategy(element);
+ this.scrollContainer = this.viewStrategy.getScrollContainer(element);
+ this.topBuffer = this.viewStrategy.createTopBufferElement(element);
+ this.bottomBuffer = this.viewStrategy.createBottomBufferElement(element);
+ this.itemsChanged();
+ this.scrollListener = function () {
+ return _this6._onScroll();
+ };
+ var containerStyle = this.scrollContainer.style;
+ if (containerStyle.overflowY === 'scroll' || containerStyle.overflow === 'scroll' || containerStyle.overflowY === 'auto' || containerStyle.overflow === 'auto') {
+ this._fixedHeightContainer = true;
+ this.scrollContainer.addEventListener('scroll', this.scrollListener);
+ } else {
+ document.addEventListener('scroll', this.scrollListener);
+ }
+ };
+
+ VirtualRepeat.prototype.bind = function bind(bindingContext, overrideContext) {
+ this.scope = { bindingContext: bindingContext, overrideContext: overrideContext };
+ this._itemsLength = this.items.length;
+ };
+
+ VirtualRepeat.prototype.call = function call(context, changes) {
+ this[context](this.items, changes);
+ };
+
+ VirtualRepeat.prototype.detached = function detached() {
+ this.scrollContainer.removeEventListener('scroll', this.scrollListener);
+ this._first = 0;
+ this._previousFirst = 0;
+ this._viewsLength = 0;
+ this._lastRebind = 0;
+ this._topBufferHeight = 0;
+ this._bottomBufferHeight = 0;
+ this._scrollingDown = false;
+ this._scrollingUp = false;
+ this._switchedDirection = false;
+ this._isAttached = false;
+ this._ticking = false;
+ this._hasCalculatedSizes = false;
+ this.viewStrategy.removeBufferElements(this.element, this.topBuffer, this.bottomBuffer);
+ this.isLastIndex = false;
+ this.scrollContainer = null;
+ this.scrollContainerHeight = null;
+ this.removeAllViews(true);
+ if (this.scrollHandler) {
+ this.scrollHandler.dispose();
+ }
+ this._unsubscribeCollection();
+ };
+
+ VirtualRepeat.prototype.itemsChanged = function itemsChanged() {
+ this._unsubscribeCollection();
+
+ if (!this.scope) {
+ return;
+ }
+ var items = this.items;
+ this.strategy = this.strategyLocator.getStrategy(items);
+ if (items.length > 0) {
+ this.strategy.createFirstItem(this);
+ }
+ this._calcInitialHeights(items.length);
+ if (!this.isOneTime && !this._observeInnerCollection()) {
+ this._observeCollection();
+ }
+
+ this.strategy.instanceChanged(this, items, this._viewsLength);
+ };
+
+ VirtualRepeat.prototype.unbind = function unbind() {
+ this.scope = null;
+ this.items = null;
+ this._itemsLength = null;
+ };
+
+ VirtualRepeat.prototype.handleCollectionMutated = function handleCollectionMutated(collection, changes) {
+ this._handlingMutations = true;
+ this._itemsLength = collection.length;
+ this.strategy.instanceMutated(this, collection, changes);
+ };
+
+ VirtualRepeat.prototype.handleInnerCollectionMutated = function handleInnerCollectionMutated(collection, changes) {
+ var _this7 = this;
+
+ if (this.ignoreMutation) {
+ return;
+ }
+ this.ignoreMutation = true;
+ var newItems = this.sourceExpression.evaluate(this.scope, this.lookupFunctions);
+ this.observerLocator.taskQueue.queueMicroTask(function () {
+ return _this7.ignoreMutation = false;
+ });
+
+ if (newItems === this.items) {
+ this.itemsChanged();
+ } else {
+ this.items = newItems;
+ }
+ };
+
+ VirtualRepeat.prototype._onScroll = function _onScroll() {
+ var _this8 = this;
+
+ if (!this._ticking && !this._handlingMutations) {
+ requestAnimationFrame(function () {
+ return _this8._handleScroll();
+ });
+ this._ticking = true;
+ }
+
+ if (this._handlingMutations) {
+ this._handlingMutations = false;
+ }
+ };
+
+ VirtualRepeat.prototype._handleScroll = function _handleScroll() {
+ if (!this._isAttached) {
+ return;
+ }
+ var itemHeight = this.itemHeight;
+ var scrollTop = this._fixedHeightContainer ? this.scrollContainer.scrollTop : pageYOffset - this.topBuffer.offsetTop;
+ this._first = Math.floor(scrollTop / itemHeight);
+ this._first = this._first < 0 ? 0 : this._first;
+ if (this._first > this.items.length - this.elementsInView) {
+ this._first = this.items.length - this.elementsInView;
+ }
+ this._checkScrolling();
+
+ if (this._scrollingDown) {
+ var viewsToMove = this._first - this._lastRebind;
+ if (this._switchedDirection) {
+ viewsToMove = this._isAtTop ? this._first : this._bufferSize - (this._lastRebind - this._first);
+ }
+ this._isAtTop = false;
+ this._lastRebind = this._first;
+ var movedViewsCount = this._moveViews(viewsToMove);
+ var adjustHeight = movedViewsCount < viewsToMove ? this._bottomBufferHeight : itemHeight * movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight + adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight - adjustHeight;
+ if (this._bottomBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ } else if (this._scrollingUp) {
+ var _viewsToMove = this._lastRebind - this._first;
+ if (this._switchedDirection) {
+ if (this.isLastIndex) {
+ _viewsToMove = this.items.length - this._first - this.elementsInView;
+ } else {
+ _viewsToMove = this._bufferSize - (this._first - this._lastRebind);
+ }
+ }
+ this.isLastIndex = false;
+ this._lastRebind = this._first;
+ var _movedViewsCount = this._moveViews(_viewsToMove);
+ this.movedViewsCount = _movedViewsCount;
+ var _adjustHeight = _movedViewsCount < _viewsToMove ? this._topBufferHeight : itemHeight * _movedViewsCount;
+ this._switchedDirection = false;
+ this._topBufferHeight = this._topBufferHeight - _adjustHeight;
+ this._bottomBufferHeight = this._bottomBufferHeight + _adjustHeight;
+ if (this._topBufferHeight >= 0) {
+ this._adjustBufferHeights();
+ }
+ }
+ this._previousFirst = this._first;
+
+ this._ticking = false;
+ };
+
+ VirtualRepeat.prototype._checkScrolling = function _checkScrolling() {
+ if (this._first > this._previousFirst && (this._bottomBufferHeight > 0 || !this.isLastIndex)) {
+ if (!this._scrollingDown) {
+ this._scrollingDown = true;
+ this._scrollingUp = false;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else if (this._first < this._previousFirst && (this._topBufferHeight >= 0 || !this._isAtTop)) {
+ if (!this._scrollingUp) {
+ this._scrollingDown = false;
+ this._scrollingUp = true;
+ this._switchedDirection = true;
+ } else {
+ this._switchedDirection = false;
+ }
+ this._isScrolling = true;
+ } else {
+ this._isScrolling = false;
+ }
+ };
+
+ VirtualRepeat.prototype._adjustBufferHeights = function _adjustBufferHeights() {
+ this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
+ };
+
+ VirtualRepeat.prototype._unsubscribeCollection = function _unsubscribeCollection() {
+ if (this.collectionObserver) {
+ this.collectionObserver.unsubscribe(this.callContext, this);
+ this.collectionObserver = null;
+ this.callContext = null;
+ }
+ };
+
+ VirtualRepeat.prototype._moveViews = function _moveViews(length) {
+ var _this9 = this;
+
+ var getNextIndex = this._scrollingDown ? function (index, i) {
+ return index + i;
+ } : function (index, i) {
+ return index - i;
+ };
+ var isAtFirstOrLastIndex = function isAtFirstOrLastIndex() {
+ return _this9._scrollingDown ? _this9.isLastIndex : _this9._isAtTop;
+ };
+ var childrenLength = this.viewCount();
+ var viewIndex = this._scrollingDown ? 0 : childrenLength - 1;
+ var items = this.items;
+ var index = this._scrollingDown ? this._getIndexOfLastView() + 1 : this._getIndexOfFirstView() - 1;
+ var i = 0;
+ while (i < length && !isAtFirstOrLastIndex()) {
+ var view = this.view(viewIndex);
+ var nextIndex = getNextIndex(index, i);
+ this.isLastIndex = nextIndex >= items.length - 1;
+ this._isAtTop = nextIndex <= 0;
+ if (!(isAtFirstOrLastIndex() && childrenLength >= items.length)) {
+ rebindAndMoveView(this, view, nextIndex, this._scrollingDown);
+ i++;
+ }
+ }
+
+ return length - (length - i);
+ };
+
+ VirtualRepeat.prototype._getIndexOfLastView = function _getIndexOfLastView() {
+ return this.view(this.viewCount() - 1).overrideContext.$index;
+ };
+
+ VirtualRepeat.prototype._getIndexOfFirstView = function _getIndexOfFirstView() {
+ return this.view(0) ? this.view(0).overrideContext.$index : -1;
+ };
+
+ VirtualRepeat.prototype._calcInitialHeights = function _calcInitialHeights(itemsLength) {
+ if (this._viewsLength > 0 && this._itemsLength === itemsLength || itemsLength <= 0) {
+ return;
+ }
+ this._hasCalculatedSizes = true;
+ this._itemsLength = itemsLength;
+ var firstViewElement = this.view(0).firstChild.nextElementSibling;
+ this.itemHeight = calcOuterHeight(firstViewElement);
+ if (this.itemHeight <= 0) {
+ throw new Error('Could not calculate item height');
+ }
+ this.scrollContainerHeight = this._fixedHeightContainer ? this._calcScrollHeight(this.scrollContainer) : document.documentElement.clientHeight;
+ this.elementsInView = Math.ceil(this.scrollContainerHeight / this.itemHeight) + 1;
+ this._viewsLength = this.elementsInView * 2 + this._bufferSize;
+ this._bottomBufferHeight = this.itemHeight * itemsLength - this.itemHeight * this._viewsLength;
+ if (this._bottomBufferHeight < 0) {
+ this._bottomBufferHeight = 0;
+ }
+ this.bottomBuffer.setAttribute('style', 'height: ' + this._bottomBufferHeight + 'px');
+ this._topBufferHeight = 0;
+ this.topBuffer.setAttribute('style', 'height: ' + this._topBufferHeight + 'px');
+
+ this.scrollContainer.scrollTop = 0;
+ this._first = 0;
+ };
+
+ VirtualRepeat.prototype._calcScrollHeight = function _calcScrollHeight(element) {
+ var height = void 0;
+ height = element.getBoundingClientRect().height;
+ height -= getStyleValue(element, 'borderTopWidth');
+ height -= getStyleValue(element, 'borderBottomWidth');
+ return height;
+ };
+
+ VirtualRepeat.prototype._observeInnerCollection = function _observeInnerCollection() {
+ var items = this._getInnerCollection();
+ var strategy = this.strategyLocator.getStrategy(items);
+ if (!strategy) {
+ return false;
+ }
+ this.collectionObserver = strategy.getCollectionObserver(this.observerLocator, items);
+ if (!this.collectionObserver) {
+ return false;
+ }
+ this.callContext = 'handleInnerCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ return true;
+ };
+
+ VirtualRepeat.prototype._getInnerCollection = function _getInnerCollection() {
+ var expression = (0, _repeatUtilities.unwrapExpression)(this.sourceExpression);
+ if (!expression) {
+ return null;
+ }
+ return expression.evaluate(this.scope, null);
+ };
+
+ VirtualRepeat.prototype._observeCollection = function _observeCollection() {
+ var items = this.items;
+ this.collectionObserver = this.strategy.getCollectionObserver(this.observerLocator, items);
+ if (this.collectionObserver) {
+ this.callContext = 'handleCollectionMutated';
+ this.collectionObserver.subscribe(this.callContext, this);
+ }
+ };
+
+ VirtualRepeat.prototype.viewCount = function viewCount() {
+ return this.viewSlot.children.length;
+ };
+
+ VirtualRepeat.prototype.views = function views() {
+ return this.viewSlot.children;
+ };
+
+ VirtualRepeat.prototype.view = function view(index) {
+ return this.viewSlot.children[index];
+ };
+
+ VirtualRepeat.prototype.addView = function addView(bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.add(view);
+ };
+
+ VirtualRepeat.prototype.insertView = function insertView(index, bindingContext, overrideContext) {
+ var view = this.viewFactory.create();
+ view.bind(bindingContext, overrideContext);
+ this.viewSlot.insert(index, view);
+ };
+
+ VirtualRepeat.prototype.removeAllViews = function removeAllViews(returnToCache, skipAnimation) {
+ return this.viewSlot.removeAll(returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.removeView = function removeView(index, returnToCache, skipAnimation) {
+ return this.viewSlot.removeAt(index, returnToCache, skipAnimation);
+ };
+
+ VirtualRepeat.prototype.updateBindings = function updateBindings(view) {
+ var j = view.bindings.length;
+ while (j--) {
+ (0, _repeatUtilities.updateOneTimeBinding)(view.bindings[j]);
+ }
+ j = view.controllers.length;
+ while (j--) {
+ var k = view.controllers[j].boundProperties.length;
+ while (k--) {
+ var binding = view.controllers[j].boundProperties[k].binding;
+ (0, _repeatUtilities.updateOneTimeBinding)(binding);
+ }
+ }
+ };
+
+ return VirtualRepeat;
+}(_aureliaTemplatingResources.AbstractRepeater), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, 'items', [_aureliaTemplating.bindable], {
+ enumerable: true,
+ initializer: null
+}), _descriptor2 = _applyDecoratedDescriptor(_class2.prototype, 'local', [_aureliaTemplating.bindable], {
+ enumerable: true,
+ initializer: null
+})), _class2)) || _class) || _class) || _class);
\ No newline at end of file
diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md
index 7d5f939..f4fd0d0 100644
--- a/doc/CHANGELOG.md
+++ b/doc/CHANGELOG.md
@@ -1,3 +1,40 @@
+## 0.4.0 (2016-03-29)
+
+
+#### Bug Fixes
+
+* **array-virtual-repeat-strategy:**
+ * add new items to the distance to bottom view port ([60383100](http://github.com/aurelia/ui-virtualization/commit/603831008f43fb1fb67a538b9191483c3a1259fc))
+ * queue changes when animating ([c4fff68b](http://github.com/aurelia/ui-virtualization/commit/c4fff68b6403eca9a3802653f77d250ce749a1ab))
+ * do not remove views when less than max rendered ([312f4caf](http://github.com/aurelia/ui-virtualization/commit/312f4caf2dac668225404e8d5dfa7602ffb87762))
+ * handel added items when scrolled to bottom ([ed3b014c](http://github.com/aurelia/ui-virtualization/commit/ed3b014c63bcafc4df5f52ea72b4426c5f057260))
+ * handle remove from bottom and top ([46c8ba71](http://github.com/aurelia/ui-virtualization/commit/46c8ba711c0455a5ba461fe2134f1f14c7af4c9d))
+* **utilities:** rename updateOverrideContexts to updateVirtualOverrideContexts ([c879a08f](http://github.com/aurelia/ui-virtualization/commit/c879a08f6f6b693fe0e4e0ba74302199c64cd6ef))
+* **view-strategy:**
+ * keep anchor node at bottom ([7857725f](http://github.com/aurelia/ui-virtualization/commit/7857725f9293b05a3a3672d6ca4902a0f050218f))
+ * handle detached ([4f10fcc5](http://github.com/aurelia/ui-virtualization/commit/4f10fcc5ed3a62cd6ea2b9a72327117c111221cc))
+* **virtual-repeat:**
+ * initialize scroll at top to true ([7264d3d6](http://github.com/aurelia/ui-virtualization/commit/7264d3d6930293dc5bb869dd47ff464f070a333f))
+ * stop updating when scrolling passed the list ([b7c19e6f](http://github.com/aurelia/ui-virtualization/commit/b7c19e6f111e4fa594d2f37d7b999039dd272a8b))
+ * move views at top and bottom when virtualised ([7775796e](http://github.com/aurelia/ui-virtualization/commit/7775796eb2586bf27c3ed08ac8e5a420db97c6e0))
+ * remove resize handling ([029e6efb](http://github.com/aurelia/ui-virtualization/commit/029e6efb21910c79a28ae6fe3c3968a39968da42))
+ * support fixed height container ([80704074](http://github.com/aurelia/ui-virtualization/commit/807040741d900e503ed205c7f2cd971110b42aeb))
+ * do not move view when at top or bottom ([dce3107a](http://github.com/aurelia/ui-virtualization/commit/dce3107a519c3d65a768b4c4221b8fa80f25b651))
+ * handle bind with less items than whats fits in view port ([9e6f121a](http://github.com/aurelia/ui-virtualization/commit/9e6f121a26c5995ea4aa5ac262274e006db17683), closes [#39](http://github.com/aurelia/ui-virtualization/issues/39))
+ * remove scrollList ([05ecd2ff](http://github.com/aurelia/ui-virtualization/commit/05ecd2ff8371c46e448af12ef9c3a5bb2cd73029))
+ * handle remove items from list ([498296b1](http://github.com/aurelia/ui-virtualization/commit/498296b1b785cbbaa0476ec0c6e932daaa00643f))
+
+
+#### Features
+
+* **TableStrategy:** remove need for surrounding container ([617d7570](http://github.com/aurelia/ui-virtualization/commit/617d7570627ae4b3ff63049a09237446f0623d52))
+* **virtual-list:** remove VirtualList ([d52201c2](http://github.com/aurelia/ui-virtualization/commit/d52201c2cee28c25728fb1e00a9f6f90f9f8fc61))
+* **virtual-repeat:**
+ * support multiple virtual-repeat after each other ([5e99c07e](http://github.com/aurelia/ui-virtualization/commit/5e99c07e3a3a382f787d90eef27c0e39750e330a))
+ * no need for surrounding container ([37c68bbd](http://github.com/aurelia/ui-virtualization/commit/37c68bbd2c5fc1b141aa97a16e40f94fcc95368e))
+ * support inline virtualization ([4805482c](http://github.com/aurelia/ui-virtualization/commit/4805482ce46199abfef694a935e3f5e092dfcc80))
+
+
### 0.3.2 (2016-03-01)
diff --git a/package.json b/package.json
index 373e590..e4fd108 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "aurelia-ui-virtualization",
- "version": "0.3.2",
+ "version": "0.4.0",
"description": "A plugin that provides a virtualized repeater and other virtualization services.",
"keywords": [
"aurelia",