Skip to content

Instantly share code, notes, and snippets.

@lperrin
Last active December 18, 2022 09:56
Show Gist options
  • Save lperrin/123be96bfff9d0a9697a to your computer and use it in GitHub Desktop.
Save lperrin/123be96bfff9d0a9697a to your computer and use it in GitHub Desktop.
app.directive('faFastScroll', ['$parse', function ($parse) {
var Interval = function(min, max) {
this.min = min || 0;
this.max = max || 0;
};
Interval.prototype.clip = function(min, max) {
if(this.max <= min || this.min >= max) {
this.min = this.max = 0;
return;
}
this.min = Math.max(this.min, min);
this.max = Math.min(this.max, max);
};
Interval.prototype.expand = function(i) {
this.min -= i;
this.max += i;
};
return {
link: function (scope, element, attrs) {
var cellHeight = parseInt(attrs.cellHeight, 10),
getter = $parse(attrs.faFastScroll);
function getVisibles(collection) {
var offset = element.scrollTop(),
range = element.height();
// strictly visible bounds
var visibles = new Interval(
Math.floor(offset / cellHeight) - 1,
Math.floor((offset + range - 1) / cellHeight)
);
// expand a bit to avoid flickers
visibles.expand(15);
visibles.clip(0, collection.length);
return visibles;
}
function updatePartialView(needDigest) {
var collection = getter(scope);
if (!collection) {
scope.partial = [];
return;
}
var visibles = getVisibles(collection);
scope.partial = collection.slice(visibles.min, visibles.max);
scope.top = visibles.min * cellHeight;
scope.bottom = (collection.length - visibles.max) * cellHeight;
// updatePartialView will be called a lot when scrolling.
// prevent $digest from propagating to individual items to save time.
if (needDigest) {
scope.$broadcast('suspend');
scope.$digest();
scope.$broadcast('resume');
}
}
element.on('scroll', function () {
updatePartialView(true);
});
scope.$watchCollection(attrs.faFastScroll, function () {
// we're already in a $digest
updatePartialView(false);
});
}
};
}]);
app.directive('faSuspendable', function () {
return {
link: function (scope) {
// FIXME: this might break is suspend/resume called out of order
// or if watchers are added while suspended
var watchers;
scope.$on('suspend', function () {
watchers = scope.$$watchers;
scope.$$watchers = [];
});
scope.$on('resume', function () {
scope.$$watchers = watchers;
watchers = void 0;
});
}
};
});
@ozknemoy
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment