2014-12-10 15:41:16 -05:00
|
|
|
'use strict';
|
|
|
|
|
2015-03-31 09:43:42 -04:00
|
|
|
var PREFETCH_ITEMS = 10;
|
|
|
|
|
2014-12-10 15:41:16 -05:00
|
|
|
var ngModule = angular.module('woDirectives');
|
|
|
|
|
2015-01-15 04:23:15 -05:00
|
|
|
ngModule.directive('listScroll', function($timeout) {
|
2014-12-10 15:41:16 -05:00
|
|
|
return {
|
|
|
|
link: function(scope, elm, attrs) {
|
|
|
|
var model = attrs.listScroll,
|
|
|
|
listEl = elm[0],
|
|
|
|
scrollTimeout;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* iterates over the mails in the mail list and loads their bodies if they are visible in the viewport
|
|
|
|
*/
|
2015-01-15 04:23:15 -05:00
|
|
|
function loadVisibleBodies() {
|
2014-12-10 15:41:16 -05:00
|
|
|
var listBorder = listEl.getBoundingClientRect(),
|
|
|
|
top = listBorder.top,
|
|
|
|
bottom = listBorder.bottom,
|
|
|
|
listItems = listEl.children[0].children,
|
|
|
|
inViewport = false,
|
|
|
|
listItem, message,
|
|
|
|
isPartiallyVisibleTop, isPartiallyVisibleBottom, isVisible,
|
2015-03-31 09:43:42 -04:00
|
|
|
displayMessages = scope[model],
|
|
|
|
visible = [],
|
|
|
|
prefetchLowerBound = displayMessages.length, // lowest index where we need to start prefetching
|
|
|
|
prefetchUpperBound = 0; // highest index where we need to start prefetching
|
2014-12-10 15:41:16 -05:00
|
|
|
|
|
|
|
if (!top && !bottom) {
|
|
|
|
// list not visible
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var i = 0, len = listItems.length; i < len; i++) {
|
|
|
|
// the n-th list item (the dom representation of an message) corresponds to
|
|
|
|
// the n-th message model in the filteredMessages array
|
|
|
|
listItem = listItems.item(i).getBoundingClientRect();
|
|
|
|
|
|
|
|
if (!displayMessages || displayMessages.length <= i) {
|
|
|
|
// stop if i get larger than the size of filtered messages
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
message = displayMessages[i];
|
|
|
|
|
|
|
|
isPartiallyVisibleTop = listItem.top < top && listItem.bottom > top; // a portion of the list item is visible on the top
|
|
|
|
isPartiallyVisibleBottom = listItem.top < bottom && listItem.bottom > bottom; // a portion of the list item is visible on the bottom
|
|
|
|
isVisible = (listItem.top || listItem.bottom) && listItem.top >= top && listItem.bottom <= bottom; // the list item is visible as a whole
|
|
|
|
|
|
|
|
if (isPartiallyVisibleTop || isVisible || isPartiallyVisibleBottom) {
|
|
|
|
// we are now iterating over visible elements
|
|
|
|
inViewport = true;
|
|
|
|
// load mail body of visible
|
2015-03-31 09:43:42 -04:00
|
|
|
visible.push(message);
|
|
|
|
|
|
|
|
prefetchLowerBound = Math.max(Math.min(prefetchLowerBound, i - 1), 0);
|
|
|
|
prefetchUpperBound = Math.max(prefetchUpperBound, i + 1);
|
2014-12-10 15:41:16 -05:00
|
|
|
} else if (inViewport) {
|
|
|
|
// we are leaving the viewport, so stop iterating over the items
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-03-31 09:43:42 -04:00
|
|
|
|
|
|
|
//
|
|
|
|
// prefetch: [prefetchLowerBound - 20 ; prefetchLowerBound] and [prefetchUpperBound; prefetchUpperBound + 20]
|
|
|
|
//
|
|
|
|
|
|
|
|
// normalize lowest index to 0, slice interprets values <0 as "start from end"
|
|
|
|
var prefetchLower = displayMessages.slice(Math.max(prefetchLowerBound - PREFETCH_ITEMS, 0), prefetchLowerBound);
|
|
|
|
var prefetchUpper = displayMessages.slice(prefetchUpperBound, prefetchUpperBound + PREFETCH_ITEMS);
|
|
|
|
|
|
|
|
visible.concat(prefetchLower).concat(prefetchUpper).forEach(function(email) {
|
|
|
|
scope.getBody([email]);
|
|
|
|
});
|
2015-01-15 04:23:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
scope.loadVisibleBodies = function() {
|
|
|
|
// wait for next tick so that scope is digested and synced to DOM
|
|
|
|
$timeout(function() {
|
|
|
|
loadVisibleBodies();
|
|
|
|
});
|
2014-12-10 15:41:16 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
// load body when scrolling
|
|
|
|
listEl.onscroll = function() {
|
|
|
|
if (scrollTimeout) {
|
|
|
|
// remove timeout so that only scroll end
|
|
|
|
clearTimeout(scrollTimeout);
|
|
|
|
}
|
|
|
|
scrollTimeout = setTimeout(function() {
|
|
|
|
scope.loadVisibleBodies();
|
|
|
|
}, 300);
|
|
|
|
};
|
|
|
|
|
|
|
|
// load the visible message bodies, when the list is re-initialized and when scrolling stopped
|
|
|
|
scope.$watchCollection(model, function() {
|
|
|
|
scope.loadVisibleBodies();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|