Skip to content

Commit a7d2245

Browse files
committed
maxIndex/minIndex refactoring
1 parent 9132956 commit a7d2245

File tree

1 file changed

+84
-50
lines changed

1 file changed

+84
-50
lines changed

src/ui-scroll.js

Lines changed: 84 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,10 @@ angular.module('ui.scroll', [])
122122
buffer.bof = false;
123123
buffer.first = origin;
124124
buffer.next = origin;
125-
buffer.minIndex = Number.MAX_VALUE;
126-
buffer.maxIndex = Number.MIN_VALUE;
125+
buffer.minIndex = origin;
126+
buffer.maxIndex = origin;
127+
buffer.minIndexUser = null;
128+
buffer.maxIndexUser = null;
127129
}
128130

129131
angular.extend(buffer, {
@@ -200,15 +202,6 @@ angular.module('ui.scroll', [])
200202
buffer.minIndex = buffer.bof ? buffer.minIndex = buffer.first : Math.min(buffer.first, buffer.minIndex);
201203
},
202204

203-
syncDatasource(datasource) {
204-
const offset = buffer.minIndex - (Math.min(buffer.minIndex, datasource.minIndex || Number.MAX_VALUE));
205-
206-
datasource.minIndex = (buffer.minIndex -= offset);
207-
datasource.maxIndex = buffer.maxIndex = Math.max(buffer.maxIndex, datasource.maxIndex || Number.MIN_VALUE);
208-
209-
return offset;
210-
},
211-
212205
// clears the buffer
213206
clear() {
214207
buffer.remove(0, buffer.length);
@@ -226,7 +219,6 @@ angular.module('ui.scroll', [])
226219
const PADDING_DEFAULT = 0.5;
227220
let topPadding = null;
228221
let bottomPadding = null;
229-
let averageItemHeight = 0;
230222
const viewport = controllers[0] && controllers[0].viewport ? controllers[0].viewport : angular.element(window);
231223

232224
viewport.css({
@@ -246,7 +238,7 @@ angular.module('ui.scroll', [])
246238
bottomPadding = new Padding(template);
247239
element.before(topPadding);
248240
element.after(bottomPadding);
249-
241+
250242
function Padding(template) {
251243
let result;
252244
let tagName = template.localName;
@@ -347,45 +339,55 @@ angular.module('ui.scroll', [])
347339
}
348340
},
349341

350-
adjustPadding() {
351-
if (!buffer.length || !cache.length) {
342+
adjustPadding(adjustScrollTop) {
343+
if (!buffer.length) {
352344
return;
353345
}
354346

347+
// percise heights calculation, items that were in buffer once
355348
let topPaddingHeight = 0;
356349
let bottomPaddingHeight = 0;
357-
for (let i = cache.length - 1; i >= 0; i--) {
358-
if(cache[i].index < buffer.first) {
359-
topPaddingHeight += cache[i].height;
360-
}
361-
if(cache[i].index >= buffer.next) {
362-
bottomPaddingHeight += cache[i].height;
350+
351+
if(cache.length) {
352+
for (let i = cache.length - 1; i >= 0; i--) {
353+
if(cache[i].index < buffer.first) {
354+
topPaddingHeight += cache[i].height;
355+
}
356+
if(cache[i].index >= buffer.next) {
357+
bottomPaddingHeight += cache[i].height;
358+
}
363359
}
364360
}
365361

366-
topPadding.height(topPaddingHeight);
367-
bottomPadding.height(bottomPaddingHeight);
368-
},
362+
// average heights calculation, items that have never been reached
363+
let topPaddingHeightAdd = 0;
364+
let bottomPaddingHeightAdd = 0;
365+
let adjustTopPadding = buffer.minIndexUser && buffer.minIndex > buffer.minIndexUser;
366+
let adjustBottomPadding = buffer.maxIndexUser && buffer.maxIndex < buffer.maxIndexUser;
369367

370-
syncDatasource(datasource) {
371-
if (!buffer.length) {
372-
return;
368+
if(adjustTopPadding || adjustBottomPadding) {
369+
let visibleItemsHeight = 0;
370+
for (let i = buffer.length - 1; i >= 0; i--) {
371+
visibleItemsHeight += buffer[i].element.outerHeight(true);
372+
}
373+
let averageItemHeight = (visibleItemsHeight + topPaddingHeight + bottomPaddingHeight) / (buffer.maxIndex - buffer.minIndex + 1);
374+
topPaddingHeightAdd = adjustTopPadding ? (buffer.minIndex - buffer.minIndexUser) * averageItemHeight : 0;
375+
bottomPaddingHeightAdd = adjustBottomPadding ? (buffer.maxIndexUser - buffer.maxIndex) * averageItemHeight : 0;
373376
}
374377

375-
const bufferFirstEl = buffer[0].element;
376-
const bufferLastEl = buffer[buffer.length - 1].element;
377-
averageItemHeight = (bufferLastEl.offset().top + bufferLastEl.outerHeight(true) - bufferFirstEl.offset().top) / buffer.length;
378+
// paddings combine adjustement
379+
let topPaddingHeightOld = topPadding.height();
380+
topPadding.height(topPaddingHeight + topPaddingHeightAdd);
381+
bottomPadding.height(bottomPaddingHeight + bottomPaddingHeightAdd);
378382

379-
const delta = buffer.syncDatasource(datasource) * averageItemHeight;
380-
381-
topPadding.height(topPadding.height() + delta);
382-
383-
viewport.scrollTop(viewport.scrollTop() + delta);
384-
385-
viewport.adjustPadding();
383+
// additional scrollTop adjustement in case of datasource.minIndex external set
384+
if (adjustScrollTop && adjustTopPadding && topPaddingHeightAdd) {
385+
let diff = topPadding.height() - topPaddingHeightOld;
386+
viewport.scrollTop(viewport.scrollTop() + diff);
387+
}
386388
},
387389

388-
adjustScrollTop(height) {
390+
adjustScrollTopAfterPrepend(height) {
389391
const paddingHeight = topPadding.height() - height;
390392

391393
if (paddingHeight >= 0) {
@@ -520,21 +522,39 @@ angular.module('ui.scroll', [])
520522
linker = linker || compileLinker;
521523

522524
const datasource = (() => {
523-
let _datasource = $parse(datasourceName)($scope);
525+
let isDatasourceValid = function () {
526+
return angular.isObject(_datasource) && angular.isFunction(_datasource.get);
527+
};
524528

529+
let _datasource = $parse(datasourceName)($scope); // try to get datasource on scope
525530
if (!isDatasourceValid()) {
526-
_datasource = $injector.get(datasourceName);
531+
_datasource = $injector.get(datasourceName); // try to inject datasource as service
527532
if (!isDatasourceValid()) {
528533
throw new Error(datasourceName + ' is not a valid datasource');
529534
}
530535
}
531536

532-
return _datasource;
537+
Object.defineProperty(_datasource, 'minIndex', {
538+
set: function (value) {
539+
this._minIndex = value;
540+
onDatasourceMinIndexChanged(value);
541+
},
542+
get: function get() {
543+
return this._minIndex;
544+
}
545+
});
533546

534-
function isDatasourceValid() {
535-
// then try to inject datasource as service
536-
return angular.isObject(_datasource) && angular.isFunction(_datasource.get);
537-
}
547+
Object.defineProperty(_datasource, 'maxIndex', {
548+
set: function (value) {
549+
this._maxIndex = value;
550+
onDatasourceMaxIndexChanged(value);
551+
},
552+
get: function get() {
553+
return this._maxIndex;
554+
}
555+
});
556+
557+
return _datasource;
538558
})();
539559

540560
let ridActual = 0;// current data revision id
@@ -547,6 +567,23 @@ angular.module('ui.scroll', [])
547567
return adjustBuffer(ridActual);
548568
});
549569

570+
var onDatasourceMinIndexChanged = function(value) {
571+
$timeout(function(){
572+
buffer.minIndexUser = value;
573+
if(!pending.length) {
574+
viewport.adjustPadding(true);
575+
}
576+
});
577+
};
578+
var onDatasourceMaxIndexChanged = function(value) {
579+
$timeout(function(){
580+
buffer.maxIndexUser = value;
581+
if(!pending.length) {
582+
viewport.adjustPadding();
583+
}
584+
});
585+
};
586+
550587
const fetchNext = (() => {
551588
if (datasource.get.length !== 2) {
552589
return (success) => datasource.get(buffer.next, bufferSize, success);
@@ -747,7 +784,7 @@ angular.module('ui.scroll', [])
747784
adjustedPaddingHeight += wrapper.element.outerHeight(true);
748785
});
749786

750-
viewport.adjustScrollTop(adjustedPaddingHeight);
787+
viewport.adjustScrollTopAfterPrepend(adjustedPaddingHeight);
751788
}
752789

753790
// re-index the buffer
@@ -762,9 +799,6 @@ angular.module('ui.scroll', [])
762799
});
763800
} else {
764801
viewport.adjustPadding();
765-
if (!pending.length) {
766-
viewport.syncDatasource(datasource);
767-
}
768802
}
769803

770804
return keepFetching;
@@ -899,4 +933,4 @@ angular.module('ui.scroll', [])
899933
};
900934
}
901935
}
902-
]);
936+
]);

0 commit comments

Comments
 (0)