|
@@ -172,13 +172,10 @@ function watchScroll(viewAreaElement, callback) {
|
|
|
|
|
|
var currentY = viewAreaElement.scrollTop;
|
|
var currentY = viewAreaElement.scrollTop;
|
|
var lastY = state.lastY;
|
|
var lastY = state.lastY;
|
|
- if (currentY > lastY) {
|
|
|
|
- state.down = true;
|
|
|
|
- } else if (currentY < lastY) {
|
|
|
|
- state.down = false;
|
|
|
|
|
|
+ if (currentY !== lastY) {
|
|
|
|
+ state.down = currentY > lastY;
|
|
}
|
|
}
|
|
state.lastY = currentY;
|
|
state.lastY = currentY;
|
|
- // else do nothing and use previous value
|
|
|
|
callback(state);
|
|
callback(state);
|
|
});
|
|
});
|
|
};
|
|
};
|
|
@@ -194,6 +191,38 @@ function watchScroll(viewAreaElement, callback) {
|
|
return state;
|
|
return state;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * Use binary search to find the index of the first item in a given array which
|
|
|
|
+ * passes a given condition. The items are expected to be sorted in the sense
|
|
|
|
+ * that if the condition is true for one item in the array, then it is also true
|
|
|
|
+ * for all following items.
|
|
|
|
+ *
|
|
|
|
+ * @returns {Number} Index of the first array element to pass the test,
|
|
|
|
+ * or |items.length| if no such element exists.
|
|
|
|
+ */
|
|
|
|
+function binarySearchFirstItem(items, condition) {
|
|
|
|
+ var minIndex = 0;
|
|
|
|
+ var maxIndex = items.length - 1;
|
|
|
|
+
|
|
|
|
+ if (items.length === 0 || !condition(items[maxIndex])) {
|
|
|
|
+ return items.length;
|
|
|
|
+ }
|
|
|
|
+ if (condition(items[minIndex])) {
|
|
|
|
+ return minIndex;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while (minIndex < maxIndex) {
|
|
|
|
+ var currentIndex = (minIndex + maxIndex) >> 1;
|
|
|
|
+ var currentItem = items[currentIndex];
|
|
|
|
+ if (condition(currentItem)) {
|
|
|
|
+ maxIndex = currentIndex;
|
|
|
|
+ } else {
|
|
|
|
+ minIndex = currentIndex + 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return minIndex; /* === maxIndex */
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Generic helper to find out what elements are visible within a scroll pane.
|
|
* Generic helper to find out what elements are visible within a scroll pane.
|
|
*/
|
|
*/
|
|
@@ -201,30 +230,45 @@ function getVisibleElements(scrollEl, views, sortByVisibility) {
|
|
var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
|
|
var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
|
|
var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
|
|
var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
|
|
|
|
|
|
- var visible = [], view;
|
|
|
|
|
|
+ function isElementBottomBelowViewTop(view) {
|
|
|
|
+ var element = view.div;
|
|
|
|
+ var elementBottom =
|
|
|
|
+ element.offsetTop + element.clientTop + element.clientHeight;
|
|
|
|
+ return elementBottom > top;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var visible = [], view, element;
|
|
var currentHeight, viewHeight, hiddenHeight, percentHeight;
|
|
var currentHeight, viewHeight, hiddenHeight, percentHeight;
|
|
var currentWidth, viewWidth;
|
|
var currentWidth, viewWidth;
|
|
- for (var i = 0, ii = views.length; i < ii; ++i) {
|
|
|
|
|
|
+ var firstVisibleElementInd = (views.length === 0) ? 0 :
|
|
|
|
+ binarySearchFirstItem(views, isElementBottomBelowViewTop);
|
|
|
|
+
|
|
|
|
+ for (var i = firstVisibleElementInd, ii = views.length; i < ii; i++) {
|
|
view = views[i];
|
|
view = views[i];
|
|
- currentHeight = view.div.offsetTop + view.div.clientTop;
|
|
|
|
- viewHeight = view.div.clientHeight;
|
|
|
|
- if ((currentHeight + viewHeight) < top) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
|
|
+ element = view.div;
|
|
|
|
+ currentHeight = element.offsetTop + element.clientTop;
|
|
|
|
+ viewHeight = element.clientHeight;
|
|
|
|
+
|
|
if (currentHeight > bottom) {
|
|
if (currentHeight > bottom) {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- currentWidth = view.div.offsetLeft + view.div.clientLeft;
|
|
|
|
- viewWidth = view.div.clientWidth;
|
|
|
|
- if ((currentWidth + viewWidth) < left || currentWidth > right) {
|
|
|
|
|
|
+
|
|
|
|
+ currentWidth = element.offsetLeft + element.clientLeft;
|
|
|
|
+ viewWidth = element.clientWidth;
|
|
|
|
+ if (currentWidth + viewWidth < left || currentWidth > right) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
hiddenHeight = Math.max(0, top - currentHeight) +
|
|
hiddenHeight = Math.max(0, top - currentHeight) +
|
|
Math.max(0, currentHeight + viewHeight - bottom);
|
|
Math.max(0, currentHeight + viewHeight - bottom);
|
|
percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
|
|
percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
|
|
|
|
|
|
- visible.push({ id: view.id, x: currentWidth, y: currentHeight,
|
|
|
|
- view: view, percent: percentHeight });
|
|
|
|
|
|
+ visible.push({
|
|
|
|
+ id: view.id,
|
|
|
|
+ x: currentWidth,
|
|
|
|
+ y: currentHeight,
|
|
|
|
+ view: view,
|
|
|
|
+ percent: percentHeight
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
var first = visible[0];
|
|
var first = visible[0];
|