import { OPERATIONS } from './utils'; export default function ScrollBuffer(elementRoutines, bufferSize, startIndex) { const buffer = Object.create(Array.prototype); angular.extend(buffer, { size: bufferSize, reset(startIndex) { buffer.remove(0, buffer.length); buffer.eof = false; buffer.bof = false; buffer.first = startIndex; buffer.next = startIndex; buffer.minIndex = startIndex; buffer.maxIndex = startIndex; buffer.minIndexUser = null; buffer.maxIndexUser = null; }, append(items) { items.forEach((item) => { ++buffer.next; buffer.insert(OPERATIONS.APPEND, item); }); buffer.maxIndex = buffer.eof ? buffer.next - 1 : Math.max(buffer.next - 1, buffer.maxIndex); }, prepend(items, immutableTop) { items.reverse().forEach((item) => { if (immutableTop) { ++buffer.next; } else { --buffer.first; } buffer.insert(OPERATIONS.PREPEND, item); }); buffer.minIndex = buffer.bof ? buffer.minIndex = buffer.first : Math.min(buffer.first, buffer.minIndex); }, /** * inserts wrapped element in the buffer * the first argument is either operation keyword (see below) or a number for operation 'insert' * for insert the number is the index for the buffer element the new one have to be inserted after * operations: 'append', 'prepend', 'insert', 'remove', 'none' */ insert(operation, item, shiftTop) { const wrapper = { item: item }; if (operation % 1 === 0) { // it is an insert wrapper.op = OPERATIONS.INSERT; buffer.splice(operation, 0, wrapper); if (shiftTop) { buffer.first--; } else { buffer.next++; } } else { wrapper.op = operation; switch (operation) { case OPERATIONS.APPEND: buffer.push(wrapper); break; case OPERATIONS.PREPEND: buffer.unshift(wrapper); break; } } }, // removes elements from buffer remove(arg1, arg2) { if (angular.isNumber(arg1)) { // removes items from arg1 (including) through arg2 (excluding) for (let i = arg1; i buffer.minIndexUser) { buffer.minIndexUser++; return; } if (buffer.minIndex === buffer.minIndexUser) { buffer.minIndexUser++; } } buffer.minIndex++; }, decrementMaxIndex() { if (buffer.maxIndexUser !== null && buffer.maxIndex { if (wrapper.element[0].offsetParent) { // element style is not display:none top = Math.min(top, wrapper.element.offset().top); bottom = Math.max(bottom, wrapper.element.offset().top + wrapper.element.outerHeight(true)); } }); return Math.max(0, bottom - top); }, getItems() { return buffer.filter(item => item.op === OPERATIONS.NONE); }, getFirstItem() { const list = buffer.getItems(); if (!list.length) { return null; } return list[0].item; }, getLastItem() { const list = buffer.getItems(); if (!list.length) { return null; } return list[list.length - 1].item; } }); buffer.reset(startIndex); return buffer; }