forked from kstam/ng-scroll-repeat
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathng-scroll-repeat.js
More file actions
126 lines (108 loc) · 4.97 KB
/
ng-scroll-repeat.js
File metadata and controls
126 lines (108 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
Angular Scroll Repeat v0.0.7 by @kstam
Copyright (c) 2014
Full source at https://github.com/kstam/ng-scroll-repeat
MIT License, https://github.com/kstam/ng-scroll-repeat/blob/master/LICENSE
*/
(function(angular) {
angular.module('ks.ngScrollRepeat', ['ks.WindowService'])
.directive('ngScrollRepeat', ['$compile', 'WindowService', function ($compile, windowService) {
'use strict';
var DEFAULT_PAGE_SIZE = 50;
var DEFAULT_TOLERANCE = 200;
var BOTTOM_REACHED_BEFORE_EVT = 'bottom-reached-before';
var BOTTOM_REACHED_AFTER_EVT = 'bottom-reached-after';
var safeApply = function(scope, fn) {
if (scope.$$phase || scope.$root.$$phase) {
fn();
} else {
scope.$apply(fn);
}
};
var verifyRepeatExpression = function (repeatExpression) {
if (repeatExpression.match(/limitTo/) || repeatExpression.match(/startFrom/)) {
throw new Error('"limitTo" and "startFrom" filters are not allowed in scroll-repeat directive');
}
};
var calculateScrollBottomDiff = function (element) {
var browserBottom = windowService.height();
var elementBottom = element.offset().top - windowService.scrollTop() + element.height();
return elementBottom - browserBottom;
};
var compile = function (tElement, tAttributes) {
var repeatExpression = tAttributes.ngScrollRepeat;
var match = repeatExpression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/);
var collectionString = match[2];
var pageSize = (tAttributes.pageSize) ? Number(tAttributes.pageSize) : DEFAULT_PAGE_SIZE;
var tolerance = (tAttributes.tolerance) ? Number(tAttributes.tolerance) : DEFAULT_TOLERANCE;
verifyRepeatExpression(repeatExpression);
tElement.removeAttr('ng-scroll-repeat');
tElement.attr('ng-repeat', repeatExpression + " | limitTo:visibleResults");
return function link($scope, $element) {
var elementParent = $($element[0]).parent();
var totalLength;
$scope.visibleResults = pageSize;
$compile($element)($scope);
$scope.$watch(collectionString, function (collection) {
totalLength = collection.length;
$scope.visibleResults = pageSize;
}, true);
$scope.$on(windowService.WINDOW_SCROLL, function () {
var diff = calculateScrollBottomDiff(elementParent);
if (diff <= tolerance && totalLength > $scope.visibleResults) {
$scope.$broadcast(BOTTOM_REACHED_BEFORE_EVT);
safeApply($scope, function() {
$scope.visibleResults += pageSize;
});
$scope.$broadcast(BOTTOM_REACHED_AFTER_EVT);
}
});
windowService.registerForScroll($scope);
$scope.$on('$destroy', function() {
windowService.deregisterForScroll($scope);
});
};
};
return {
replace: false,
terminal: true,
priority: 2000,
restrict: 'A',
compile: compile
};
}]);
}(window.angular));
(function(angular) {
angular.module('ks.WindowService', [])
.factory('WindowService', ['$window', function ($window) {
var windowElement = angular.element($window);
var WINDOW_SCROLL = 'WINDOW_SCROLL';
var listeners = [];
windowElement.on('scroll', function () {
var scope;
for (var index in listeners) {
scope = listeners[index];
scope.$broadcast(WINDOW_SCROLL);
}
});
return {
WINDOW_SCROLL: WINDOW_SCROLL,
height: function () {
return windowElement.height();
},
scrollTop: function () {
return windowElement.scrollTop();
},
registerForScroll: function ($scope) {
if ($scope && angular.isFunction($scope.$broadcast)) {
listeners.push($scope);
} else {
throw new Error('Cannot register a non-scope object for scroll');
}
},
deregisterForScroll: function ($scope) {
listeners.splice(listeners.indexOf($scope), 1);
}
};
}]);
}(window.angular));