~ltrager/maas/rootfs_over_http

« back to all changes in this revision

Viewing changes to src/maasserver/static/js/angular/3rdparty/vs-repeat.js

  • Committer: Lee Trager
  • Date: 2017-06-16 14:55:02 UTC
  • mfrom: (6085.1.7 maas)
  • Revision ID: lee.trager@canonical.com-20170616145502-eiee6v1mz3pckzue
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Copyright Kamil Pękala http://github.com/kamilkp
 
3
// Angular Virtual Scroll Repeat v1.1.7 2016/03/08
 
4
//
 
5
 
 
6
(function(window, angular) {
 
7
    'use strict';
 
8
    /* jshint eqnull:true */
 
9
    /* jshint -W038 */
 
10
 
 
11
    // DESCRIPTION:
 
12
    // vsRepeat directive stands for Virtual Scroll Repeat. It turns a standard ngRepeated set of elements in a scrollable container
 
13
    // into a component, where the user thinks he has all the elements rendered and all he needs to do is scroll (without any kind of
 
14
    // pagination - which most users loath) and at the same time the browser isn't overloaded by that many elements/angular bindings etc.
 
15
    // The directive renders only so many elements that can fit into current container's clientHeight/clientWidth.
 
16
 
 
17
    // LIMITATIONS:
 
18
    // - current version only supports an Array as a right-hand-side object for ngRepeat
 
19
    // - all rendered elements must have the same height/width or the sizes of the elements must be known up front
 
20
 
 
21
    // USAGE:
 
22
    // In order to use the vsRepeat directive you need to place a vs-repeat attribute on a direct parent of an element with ng-repeat
 
23
    // example:
 
24
    // <div vs-repeat>
 
25
    //      <div ng-repeat="item in someArray">
 
26
    //          <!-- content -->
 
27
    //      </div>
 
28
    // </div>
 
29
    //
 
30
    // or:
 
31
    // <div vs-repeat>
 
32
    //      <div ng-repeat-start="item in someArray">
 
33
    //          <!-- content -->
 
34
    //      </div>
 
35
    //      <div>
 
36
    //         <!-- something in the middle -->
 
37
    //      </div>
 
38
    //      <div ng-repeat-end>
 
39
    //          <!-- content -->
 
40
    //      </div>
 
41
    // </div>
 
42
    //
 
43
    // You can also measure the single element's height/width (including all paddings and margins), and then speficy it as a value
 
44
    // of the attribute 'vs-repeat'. This can be used if one wants to override the automatically computed element size.
 
45
    // example:
 
46
    // <div vs-repeat="50"> <!-- the specified element height is 50px -->
 
47
    //      <div ng-repeat="item in someArray">
 
48
    //          <!-- content -->
 
49
    //      </div>
 
50
    // </div>
 
51
    //
 
52
    // IMPORTANT!
 
53
    //
 
54
    // - the vsRepeat directive must be applied to a direct parent of an element with ngRepeat
 
55
    // - the value of vsRepeat attribute is the single element's height/width measured in pixels. If none provided, the directive
 
56
    //      will compute it automatically
 
57
 
 
58
    // OPTIONAL PARAMETERS (attributes):
 
59
    // vs-repeat-container="selector" - selector for element containing ng-repeat. (defaults to the current element)
 
60
    // vs-scroll-parent="selector" - selector to the scrollable container. The directive will look for a closest parent matching
 
61
    //                              the given selector (defaults to the current element)
 
62
    // vs-horizontal - stack repeated elements horizontally instead of vertically
 
63
    // vs-offset-before="value" - top/left offset in pixels (defaults to 0)
 
64
    // vs-offset-after="value" - bottom/right offset in pixels (defaults to 0)
 
65
    // vs-excess="value" - an integer number representing the number of elements to be rendered outside of the current container's viewport
 
66
    //                      (defaults to 2)
 
67
    // vs-size - a property name of the items in collection that is a number denoting the element size (in pixels)
 
68
    // vs-autoresize - use this attribute without vs-size and without specifying element's size. The automatically computed element style will
 
69
    //              readjust upon window resize if the size is dependable on the viewport size
 
70
    // vs-scrolled-to-end="callback" - callback will be called when the last item of the list is rendered
 
71
    // vs-scrolled-to-end-offset="integer" - set this number to trigger the scrolledToEnd callback n items before the last gets rendered
 
72
    // vs-scrolled-to-beginning="callback" - callback will be called when the first item of the list is rendered
 
73
    // vs-scrolled-to-beginning-offset="integer" - set this number to trigger the scrolledToBeginning callback n items before the first gets rendered
 
74
 
 
75
    // EVENTS:
 
76
    // - 'vsRepeatTrigger' - an event the directive listens for to manually trigger reinitialization
 
77
    // - 'vsRepeatReinitialized' - an event the directive emits upon reinitialization done
 
78
 
 
79
    var dde = document.documentElement,
 
80
        matchingFunction = dde.matches ? 'matches' :
 
81
                            dde.matchesSelector ? 'matchesSelector' :
 
82
                            dde.webkitMatches ? 'webkitMatches' :
 
83
                            dde.webkitMatchesSelector ? 'webkitMatchesSelector' :
 
84
                            dde.msMatches ? 'msMatches' :
 
85
                            dde.msMatchesSelector ? 'msMatchesSelector' :
 
86
                            dde.mozMatches ? 'mozMatches' :
 
87
                            dde.mozMatchesSelector ? 'mozMatchesSelector' : null;
 
88
 
 
89
    var closestElement = angular.element.prototype.closest || function (selector) {
 
90
        var el = this[0].parentNode;
 
91
        while (el !== document.documentElement && el != null && !el[matchingFunction](selector)) {
 
92
            el = el.parentNode;
 
93
        }
 
94
 
 
95
        if (el && el[matchingFunction](selector)) {
 
96
            return angular.element(el);
 
97
        }
 
98
        else {
 
99
            return angular.element();
 
100
        }
 
101
    };
 
102
 
 
103
    function getWindowScroll() {
 
104
        if ('pageYOffset' in window) {
 
105
            return {
 
106
                scrollTop: pageYOffset,
 
107
                scrollLeft: pageXOffset
 
108
            };
 
109
        }
 
110
        else {
 
111
            var sx, sy, d = document, r = d.documentElement, b = d.body;
 
112
            sx = r.scrollLeft || b.scrollLeft || 0;
 
113
            sy = r.scrollTop || b.scrollTop || 0;
 
114
            return {
 
115
                scrollTop: sy,
 
116
                scrollLeft: sx
 
117
            };
 
118
        }
 
119
    }
 
120
 
 
121
    function getClientSize(element, sizeProp) {
 
122
        if (element === window) {
 
123
            return sizeProp === 'clientWidth' ? window.innerWidth : window.innerHeight;
 
124
        }
 
125
        else {
 
126
            return element[sizeProp];
 
127
        }
 
128
    }
 
129
 
 
130
    function getScrollPos(element, scrollProp) {
 
131
        return element === window ? getWindowScroll()[scrollProp] : element[scrollProp];
 
132
    }
 
133
 
 
134
    function getScrollOffset(vsElement, scrollElement, isHorizontal) {
 
135
        var vsPos = vsElement.getBoundingClientRect()[isHorizontal ? 'left' : 'top'];
 
136
        var scrollPos = scrollElement === window ? 0 : scrollElement.getBoundingClientRect()[isHorizontal ? 'left' : 'top'];
 
137
        var correction = vsPos - scrollPos +
 
138
            (scrollElement === window ? getWindowScroll() : scrollElement)[isHorizontal ? 'scrollLeft' : 'scrollTop'];
 
139
 
 
140
        return correction;
 
141
    }
 
142
 
 
143
    var vsRepeatModule = angular.module('vs-repeat', []).directive('vsRepeat', ['$compile', '$parse', function($compile, $parse) {
 
144
        return {
 
145
            restrict: 'A',
 
146
            scope: true,
 
147
            compile: function($element, $attrs) {
 
148
                var repeatContainer = angular.isDefined($attrs.vsRepeatContainer) ? angular.element($element[0].querySelector($attrs.vsRepeatContainer)) : $element,
 
149
                    ngRepeatChild = repeatContainer.children().eq(0),
 
150
                    ngRepeatExpression,
 
151
                    childCloneHtml = ngRepeatChild[0].outerHTML,
 
152
                    expressionMatches,
 
153
                    lhs,
 
154
                    rhs,
 
155
                    rhsSuffix,
 
156
                    originalNgRepeatAttr,
 
157
                    collectionName = '$vs_collection',
 
158
                    isNgRepeatStart = false,
 
159
                    attributesDictionary = {
 
160
                        'vsRepeat': 'elementSize',
 
161
                        'vsOffsetBefore': 'offsetBefore',
 
162
                        'vsOffsetAfter': 'offsetAfter',
 
163
                        'vsScrolledToEndOffset': 'scrolledToEndOffset',
 
164
                        'vsScrolledToBeginningOffset': 'scrolledToBeginningOffset',
 
165
                        'vsExcess': 'excess'
 
166
                    };
 
167
 
 
168
                if (ngRepeatChild.attr('ng-repeat')) {
 
169
                    originalNgRepeatAttr = 'ng-repeat';
 
170
                    ngRepeatExpression = ngRepeatChild.attr('ng-repeat');
 
171
                }
 
172
                else if (ngRepeatChild.attr('data-ng-repeat')) {
 
173
                    originalNgRepeatAttr = 'data-ng-repeat';
 
174
                    ngRepeatExpression = ngRepeatChild.attr('data-ng-repeat');
 
175
                }
 
176
                else if (ngRepeatChild.attr('ng-repeat-start')) {
 
177
                    isNgRepeatStart = true;
 
178
                    originalNgRepeatAttr = 'ng-repeat-start';
 
179
                    ngRepeatExpression = ngRepeatChild.attr('ng-repeat-start');
 
180
                }
 
181
                else if (ngRepeatChild.attr('data-ng-repeat-start')) {
 
182
                    isNgRepeatStart = true;
 
183
                    originalNgRepeatAttr = 'data-ng-repeat-start';
 
184
                    ngRepeatExpression = ngRepeatChild.attr('data-ng-repeat-start');
 
185
                }
 
186
                else {
 
187
                    throw new Error('angular-vs-repeat: no ng-repeat directive on a child element');
 
188
                }
 
189
 
 
190
                expressionMatches = /^\s*(\S+)\s+in\s+([\S\s]+?)(track\s+by\s+\S+)?$/.exec(ngRepeatExpression);
 
191
                lhs = expressionMatches[1];
 
192
                rhs = expressionMatches[2];
 
193
                rhsSuffix = expressionMatches[3];
 
194
 
 
195
                if (isNgRepeatStart) {
 
196
                    var index = 0;
 
197
                    var repeaterElement = repeatContainer.children().eq(0);
 
198
                    while(repeaterElement.attr('ng-repeat-end') == null && repeaterElement.attr('data-ng-repeat-end') == null) {
 
199
                        index++;
 
200
                        repeaterElement = repeatContainer.children().eq(index);
 
201
                        childCloneHtml += repeaterElement[0].outerHTML;
 
202
                    }
 
203
                }
 
204
 
 
205
                repeatContainer.empty();
 
206
                return {
 
207
                    pre: function($scope, $element, $attrs) {
 
208
                        var repeatContainer = angular.isDefined($attrs.vsRepeatContainer) ? angular.element($element[0].querySelector($attrs.vsRepeatContainer)) : $element,
 
209
                            childClone = angular.element(childCloneHtml),
 
210
                            childTagName = childClone[0].tagName.toLowerCase(),
 
211
                            originalCollection = [],
 
212
                            originalLength,
 
213
                            $$horizontal = typeof $attrs.vsHorizontal !== 'undefined',
 
214
                            $beforeContent = angular.element('<' + childTagName + ' class="vs-repeat-before-content"></' + childTagName + '>'),
 
215
                            $afterContent = angular.element('<' + childTagName + ' class="vs-repeat-after-content"></' + childTagName + '>'),
 
216
                            autoSize = !$attrs.vsRepeat,
 
217
                            sizesPropertyExists = !!$attrs.vsSize || !!$attrs.vsSizeProperty,
 
218
                            $scrollParent = $attrs.vsScrollParent ?
 
219
                                $attrs.vsScrollParent === 'window' ? angular.element(window) :
 
220
                                closestElement.call(repeatContainer, $attrs.vsScrollParent) : repeatContainer,
 
221
                            $$options = 'vsOptions' in $attrs ? $scope.$eval($attrs.vsOptions) : {},
 
222
                            clientSize = $$horizontal ? 'clientWidth' : 'clientHeight',
 
223
                            offsetSize = $$horizontal ? 'offsetWidth' : 'offsetHeight',
 
224
                            scrollPos = $$horizontal ? 'scrollLeft' : 'scrollTop';
 
225
 
 
226
                        $scope.totalSize = 0;
 
227
                        if (!('vsSize' in $attrs) && 'vsSizeProperty' in $attrs) {
 
228
                            console.warn('vs-size-property attribute is deprecated. Please use vs-size attribute which also accepts angular expressions.');
 
229
                        }
 
230
 
 
231
                        if ($scrollParent.length === 0) {
 
232
                            throw 'Specified scroll parent selector did not match any element';
 
233
                        }
 
234
                        $scope.$scrollParent = $scrollParent;
 
235
 
 
236
                        if (sizesPropertyExists) {
 
237
                            $scope.sizesCumulative = [];
 
238
                        }
 
239
 
 
240
                        //initial defaults
 
241
                        $scope.elementSize = (+$attrs.vsRepeat) || getClientSize($scrollParent[0], clientSize) || 50;
 
242
                        $scope.offsetBefore = 0;
 
243
                        $scope.offsetAfter = 0;
 
244
                        $scope.excess = 2;
 
245
 
 
246
                        if ($$horizontal) {
 
247
                            $beforeContent.css('height', '100%');
 
248
                            $afterContent.css('height', '100%');
 
249
                        }
 
250
                        else {
 
251
                            $beforeContent.css('width', '100%');
 
252
                            $afterContent.css('width', '100%');
 
253
                        }
 
254
 
 
255
                        Object.keys(attributesDictionary).forEach(function(key) {
 
256
                            if ($attrs[key]) {
 
257
                                $attrs.$observe(key, function(value) {
 
258
                                    // '+' serves for getting a number from the string as the attributes are always strings
 
259
                                    $scope[attributesDictionary[key]] = +value;
 
260
                                    reinitialize();
 
261
                                });
 
262
                            }
 
263
                        });
 
264
 
 
265
 
 
266
                        $scope.$watchCollection(rhs, function(coll) {
 
267
                            originalCollection = coll || [];
 
268
                            refresh();
 
269
                        });
 
270
 
 
271
                        function refresh() {
 
272
                            if (!originalCollection || originalCollection.length < 1) {
 
273
                                $scope[collectionName] = [];
 
274
                                originalLength = 0;
 
275
                                $scope.sizesCumulative = [0];
 
276
                            }
 
277
                            else {
 
278
                                originalLength = originalCollection.length;
 
279
                                if (sizesPropertyExists) {
 
280
                                    $scope.sizes = originalCollection.map(function(item) {
 
281
                                        var s = $scope.$new(false);
 
282
                                        angular.extend(s, item);
 
283
                                        s[lhs] = item;
 
284
                                        var size = ($attrs.vsSize || $attrs.vsSizeProperty) ?
 
285
                                                        s.$eval($attrs.vsSize || $attrs.vsSizeProperty) :
 
286
                                                        $scope.elementSize;
 
287
                                        s.$destroy();
 
288
                                        return size;
 
289
                                    });
 
290
                                    var sum = 0;
 
291
                                    $scope.sizesCumulative = $scope.sizes.map(function(size) {
 
292
                                        var res = sum;
 
293
                                        sum += size;
 
294
                                        return res;
 
295
                                    });
 
296
                                    $scope.sizesCumulative.push(sum);
 
297
                                }
 
298
                                else {
 
299
                                    setAutoSize();
 
300
                                }
 
301
                            }
 
302
 
 
303
                            reinitialize();
 
304
                        }
 
305
 
 
306
                        function setAutoSize() {
 
307
                            if (autoSize) {
 
308
                                $scope.$$postDigest(function() {
 
309
                                    if (repeatContainer[0].offsetHeight || repeatContainer[0].offsetWidth) { // element is visible
 
310
                                        var children = repeatContainer.children(),
 
311
                                            i = 0,
 
312
                                            gotSomething = false,
 
313
                                            insideStartEndSequence = false;
 
314
 
 
315
                                        while (i < children.length) {
 
316
                                            if (children[i].attributes[originalNgRepeatAttr] != null || insideStartEndSequence) {
 
317
                                                if (!gotSomething) {
 
318
                                                    $scope.elementSize = 0;
 
319
                                                }
 
320
 
 
321
                                                gotSomething = true;
 
322
                                                if (children[i][offsetSize]) {
 
323
                                                    $scope.elementSize += children[i][offsetSize];
 
324
                                                }
 
325
 
 
326
                                                if (isNgRepeatStart) {
 
327
                                                    if (children[i].attributes['ng-repeat-end'] != null || children[i].attributes['data-ng-repeat-end'] != null) {
 
328
                                                        break;
 
329
                                                    }
 
330
                                                    else {
 
331
                                                        insideStartEndSequence = true;
 
332
                                                    }
 
333
                                                }
 
334
                                                else {
 
335
                                                    break;
 
336
                                                }
 
337
                                            }
 
338
                                            i++;
 
339
                                        }
 
340
 
 
341
                                        if (gotSomething) {
 
342
                                            reinitialize();
 
343
                                            autoSize = false;
 
344
                                            if ($scope.$root && !$scope.$root.$$phase) {
 
345
                                                $scope.$apply();
 
346
                                            }
 
347
                                        }
 
348
                                    }
 
349
                                    else {
 
350
                                        var dereg = $scope.$watch(function() {
 
351
                                            if (repeatContainer[0].offsetHeight || repeatContainer[0].offsetWidth) {
 
352
                                                dereg();
 
353
                                                setAutoSize();
 
354
                                            }
 
355
                                        });
 
356
                                    }
 
357
                                });
 
358
                            }
 
359
                        }
 
360
 
 
361
                        function getLayoutProp() {
 
362
                            var layoutPropPrefix = childTagName === 'tr' ? '' : 'min-';
 
363
                            var layoutProp = $$horizontal ? layoutPropPrefix + 'width' : layoutPropPrefix + 'height';
 
364
                            return layoutProp;
 
365
                        }
 
366
 
 
367
                        childClone.eq(0).attr(originalNgRepeatAttr, lhs + ' in ' + collectionName + (rhsSuffix ? ' ' + rhsSuffix : ''));
 
368
                        childClone.addClass('vs-repeat-repeated-element');
 
369
 
 
370
                        repeatContainer.append($beforeContent);
 
371
                        repeatContainer.append(childClone);
 
372
                        $compile(childClone)($scope);
 
373
                        repeatContainer.append($afterContent);
 
374
 
 
375
                        $scope.startIndex = 0;
 
376
                        $scope.endIndex = 0;
 
377
 
 
378
                        function scrollHandler() {
 
379
                            if (updateInnerCollection()) {
 
380
                                $scope.$digest();
 
381
                            }
 
382
                        }
 
383
 
 
384
                        $scrollParent.on('scroll', scrollHandler);
 
385
 
 
386
                        function onWindowResize() {
 
387
                            if (typeof $attrs.vsAutoresize !== 'undefined') {
 
388
                                autoSize = true;
 
389
                                setAutoSize();
 
390
                                if ($scope.$root && !$scope.$root.$$phase) {
 
391
                                    $scope.$apply();
 
392
                                }
 
393
                            }
 
394
                            if (updateInnerCollection()) {
 
395
                                $scope.$apply();
 
396
                            }
 
397
                        }
 
398
 
 
399
                        angular.element(window).on('resize', onWindowResize);
 
400
                        $scope.$on('$destroy', function() {
 
401
                            angular.element(window).off('resize', onWindowResize);
 
402
                            $scrollParent.off('scroll', scrollHandler);
 
403
                        });
 
404
 
 
405
                        $scope.$on('vsRepeatTrigger', refresh);
 
406
 
 
407
                        $scope.$on('vsRepeatResize', function() {
 
408
                            autoSize = true;
 
409
                            setAutoSize();
 
410
                        });
 
411
 
 
412
                        var _prevStartIndex,
 
413
                            _prevEndIndex,
 
414
                            _minStartIndex,
 
415
                            _maxEndIndex;
 
416
 
 
417
                        $scope.$on('vsRenderAll', function() {//e , quantum) {
 
418
                            if($$options.latch) {
 
419
                                setTimeout(function() {
 
420
                                    // var __endIndex = Math.min($scope.endIndex + (quantum || 1), originalLength);
 
421
                                    var __endIndex = originalLength;
 
422
                                    _maxEndIndex = Math.max(__endIndex, _maxEndIndex);
 
423
                                    $scope.endIndex = $$options.latch ? _maxEndIndex : __endIndex;
 
424
                                    $scope[collectionName] = originalCollection.slice($scope.startIndex, $scope.endIndex);
 
425
                                    _prevEndIndex = $scope.endIndex;
 
426
 
 
427
                                    $scope.$$postDigest(function() {
 
428
                                        $beforeContent.css(getLayoutProp(), 0);
 
429
                                        $afterContent.css(getLayoutProp(), 0);
 
430
                                    });
 
431
 
 
432
                                    $scope.$apply(function() {
 
433
                                        $scope.$emit('vsRenderAllDone');
 
434
                                    });
 
435
                                });
 
436
                            }
 
437
                        });
 
438
 
 
439
                        function reinitialize() {
 
440
                            _prevStartIndex = void 0;
 
441
                            _prevEndIndex = void 0;
 
442
                            _minStartIndex = originalLength;
 
443
                            _maxEndIndex = 0;
 
444
                            updateTotalSize(sizesPropertyExists ?
 
445
                                                $scope.sizesCumulative[originalLength] :
 
446
                                                $scope.elementSize * originalLength
 
447
                                            );
 
448
                            updateInnerCollection();
 
449
 
 
450
                            $scope.$emit('vsRepeatReinitialized', $scope.startIndex, $scope.endIndex);
 
451
                        }
 
452
 
 
453
                        function updateTotalSize(size) {
 
454
                            $scope.totalSize = $scope.offsetBefore + size + $scope.offsetAfter;
 
455
                        }
 
456
 
 
457
                        var _prevClientSize;
 
458
                        function reinitOnClientHeightChange() {
 
459
                            var ch = getClientSize($scrollParent[0], clientSize);
 
460
                            if (ch !== _prevClientSize) {
 
461
                                reinitialize();
 
462
                                if ($scope.$root && !$scope.$root.$$phase) {
 
463
                                    $scope.$apply();
 
464
                                }
 
465
                            }
 
466
                            _prevClientSize = ch;
 
467
                        }
 
468
 
 
469
                        $scope.$watch(function() {
 
470
                            if (typeof window.requestAnimationFrame === 'function') {
 
471
                                window.requestAnimationFrame(reinitOnClientHeightChange);
 
472
                            }
 
473
                            else {
 
474
                                reinitOnClientHeightChange();
 
475
                            }
 
476
                        });
 
477
 
 
478
                        function updateInnerCollection() {
 
479
                            var $scrollPosition = getScrollPos($scrollParent[0], scrollPos);
 
480
                            var $clientSize = getClientSize($scrollParent[0], clientSize);
 
481
 
 
482
                            var scrollOffset = repeatContainer[0] === $scrollParent[0] ? 0 : getScrollOffset(
 
483
                                                    repeatContainer[0],
 
484
                                                    $scrollParent[0],
 
485
                                                    $$horizontal
 
486
                                                );
 
487
 
 
488
                            var __startIndex = $scope.startIndex;
 
489
                            var __endIndex = $scope.endIndex;
 
490
 
 
491
                            if (sizesPropertyExists) {
 
492
                                __startIndex = 0;
 
493
                                while ($scope.sizesCumulative[__startIndex] < $scrollPosition - $scope.offsetBefore - scrollOffset) {
 
494
                                    __startIndex++;
 
495
                                }
 
496
                                if (__startIndex > 0) { __startIndex--; }
 
497
 
 
498
                                // Adjust the start index according to the excess
 
499
                                __startIndex = Math.max(
 
500
                                    Math.floor(__startIndex - $scope.excess / 2),
 
501
                                    0
 
502
                                );
 
503
 
 
504
                                __endIndex = __startIndex;
 
505
                                while ($scope.sizesCumulative[__endIndex] < $scrollPosition - $scope.offsetBefore - scrollOffset + $clientSize) {
 
506
                                    __endIndex++;
 
507
                                }
 
508
 
 
509
                                // Adjust the end index according to the excess
 
510
                                __endIndex = Math.min(
 
511
                                    Math.ceil(__endIndex + $scope.excess / 2),
 
512
                                    originalLength
 
513
                                );
 
514
                            }
 
515
                            else {
 
516
                                __startIndex = Math.max(
 
517
                                    Math.floor(
 
518
                                        ($scrollPosition - $scope.offsetBefore - scrollOffset) / $scope.elementSize
 
519
                                    ) - $scope.excess / 2,
 
520
                                    0
 
521
                                );
 
522
 
 
523
                                __endIndex = Math.min(
 
524
                                    __startIndex + Math.ceil(
 
525
                                        $clientSize / $scope.elementSize
 
526
                                    ) + $scope.excess,
 
527
                                    originalLength
 
528
                                );
 
529
                            }
 
530
 
 
531
                            _minStartIndex = Math.min(__startIndex, _minStartIndex);
 
532
                            _maxEndIndex = Math.max(__endIndex, _maxEndIndex);
 
533
 
 
534
                            $scope.startIndex = $$options.latch ? _minStartIndex : __startIndex;
 
535
                            $scope.endIndex = $$options.latch ? _maxEndIndex : __endIndex;
 
536
 
 
537
                            var digestRequired = false;
 
538
                            if (_prevStartIndex == null) {
 
539
                                digestRequired = true;
 
540
                            }
 
541
                            else if (_prevEndIndex == null) {
 
542
                                digestRequired = true;
 
543
                            }
 
544
 
 
545
                            if (!digestRequired) {
 
546
                                if ($$options.hunked) {
 
547
                                    if (Math.abs($scope.startIndex - _prevStartIndex) >= $scope.excess / 2 ||
 
548
                                        ($scope.startIndex === 0 && _prevStartIndex !== 0)) {
 
549
                                        digestRequired = true;
 
550
                                    }
 
551
                                    else if (Math.abs($scope.endIndex - _prevEndIndex) >= $scope.excess / 2 ||
 
552
                                        ($scope.endIndex === originalLength && _prevEndIndex !== originalLength)) {
 
553
                                        digestRequired = true;
 
554
                                    }
 
555
                                }
 
556
                                else {
 
557
                                    digestRequired = $scope.startIndex !== _prevStartIndex ||
 
558
                                                        $scope.endIndex !== _prevEndIndex;
 
559
                                }
 
560
                            }
 
561
 
 
562
                            if (digestRequired) {
 
563
                                $scope[collectionName] = originalCollection.slice($scope.startIndex, $scope.endIndex);
 
564
 
 
565
                                // Emit the event
 
566
                                $scope.$emit('vsRepeatInnerCollectionUpdated', $scope.startIndex, $scope.endIndex, _prevStartIndex, _prevEndIndex);
 
567
                                var triggerIndex;
 
568
                                if ($attrs.vsScrolledToEnd) {
 
569
                                    triggerIndex = originalCollection.length - ($scope.scrolledToEndOffset || 0);
 
570
                                    if (($scope.endIndex >= triggerIndex && _prevEndIndex < triggerIndex) || (originalCollection.length && $scope.endIndex === originalCollection.length)) {
 
571
                                        $scope.$eval($attrs.vsScrolledToEnd);
 
572
                                    }
 
573
                                }
 
574
                                if ($attrs.vsScrolledToBeginning) {
 
575
                                    triggerIndex = $scope.scrolledToBeginningOffset || 0;
 
576
                                    if (($scope.startIndex <= triggerIndex && _prevStartIndex > $scope.startIndex)) {
 
577
                                        $scope.$eval($attrs.vsScrolledToBeginning);
 
578
                                    }
 
579
                                }
 
580
 
 
581
                                _prevStartIndex = $scope.startIndex;
 
582
                                _prevEndIndex = $scope.endIndex;
 
583
 
 
584
                                var offsetCalculationString = sizesPropertyExists ?
 
585
                                    '(sizesCumulative[$index + startIndex] + offsetBefore)' :
 
586
                                    '(($index + startIndex) * elementSize + offsetBefore)';
 
587
 
 
588
                                var parsed = $parse(offsetCalculationString);
 
589
                                var o1 = parsed($scope, {$index: 0});
 
590
                                var o2 = parsed($scope, {$index: $scope[collectionName].length});
 
591
                                var total = $scope.totalSize;
 
592
 
 
593
                                $beforeContent.css(getLayoutProp(), o1 + 'px');
 
594
                                $afterContent.css(getLayoutProp(), (total - o2) + 'px');
 
595
                            }
 
596
 
 
597
                            return digestRequired;
 
598
                        }
 
599
                    }
 
600
                };
 
601
            }
 
602
        };
 
603
    }]);
 
604
 
 
605
    if (typeof module !== 'undefined' && module.exports) {
 
606
        module.exports = vsRepeatModule.name;
 
607
    }
 
608
})(window, window.angular);