mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
rewrite output scrolling service
This commit is contained in:
parent
4c3370bd34
commit
fed729f101
@ -74,6 +74,12 @@
|
||||
color: @at-blue;
|
||||
}
|
||||
|
||||
&-menuIconStack--wrapper {
|
||||
&:hover {
|
||||
color: @at-blue;
|
||||
}
|
||||
}
|
||||
|
||||
&-row {
|
||||
display: flex;
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ import {
|
||||
} from './constants';
|
||||
|
||||
const BASE_PARAMS = {
|
||||
order_by: OUTPUT_ORDER_BY,
|
||||
page_size: OUTPUT_PAGE_SIZE,
|
||||
order_by: OUTPUT_ORDER_BY,
|
||||
};
|
||||
|
||||
const merge = (...objs) => _.merge({}, ...objs);
|
||||
@ -20,12 +20,6 @@ function JobEventsApiService ($http, $q) {
|
||||
this.cache = {};
|
||||
};
|
||||
|
||||
this.clearCache = () => {
|
||||
Object.keys(this.cache).forEach(key => {
|
||||
delete this.cache[key];
|
||||
});
|
||||
};
|
||||
|
||||
this.fetch = () => this.getLast()
|
||||
.then(results => {
|
||||
this.cache.last = results;
|
||||
@ -33,20 +27,31 @@ function JobEventsApiService ($http, $q) {
|
||||
return this;
|
||||
});
|
||||
|
||||
this.clearCache = () => {
|
||||
Object.keys(this.cache).forEach(key => {
|
||||
delete this.cache[key];
|
||||
});
|
||||
};
|
||||
|
||||
this.pushMaxCounter = events => {
|
||||
const maxCounter = Math.max(...events.map(({ counter }) => counter));
|
||||
|
||||
if (maxCounter > this.state.maxCounter) {
|
||||
this.state.maxCounter = maxCounter;
|
||||
}
|
||||
|
||||
return maxCounter;
|
||||
};
|
||||
|
||||
this.getFirst = () => {
|
||||
const page = 1;
|
||||
const params = merge(this.params, { page });
|
||||
const params = merge(this.params, { page: 1 });
|
||||
|
||||
return $http.get(this.endpoint, { params })
|
||||
.then(({ data }) => {
|
||||
const { results, count } = data;
|
||||
const maxCounter = Math.max(...results.map(({ counter }) => counter));
|
||||
|
||||
this.state.count = count;
|
||||
|
||||
if (maxCounter > this.state.maxCounter) {
|
||||
this.state.maxCounter = maxCounter;
|
||||
}
|
||||
this.pushMaxCounter(results);
|
||||
|
||||
return results;
|
||||
});
|
||||
@ -62,13 +67,9 @@ function JobEventsApiService ($http, $q) {
|
||||
return $http.get(this.endpoint, { params })
|
||||
.then(({ data }) => {
|
||||
const { results, count } = data;
|
||||
const maxCounter = Math.max(...results.map(({ counter }) => counter));
|
||||
|
||||
this.state.count = count;
|
||||
|
||||
if (maxCounter > this.state.maxCounter) {
|
||||
this.state.maxCounter = maxCounter;
|
||||
}
|
||||
this.pushMaxCounter(results);
|
||||
|
||||
return results;
|
||||
});
|
||||
@ -84,7 +85,6 @@ function JobEventsApiService ($http, $q) {
|
||||
return $http.get(this.endpoint, { params })
|
||||
.then(({ data }) => {
|
||||
const { results, count } = data;
|
||||
const maxCounter = Math.max(...results.map(({ counter }) => counter));
|
||||
|
||||
let rotated = results;
|
||||
|
||||
@ -97,10 +97,7 @@ function JobEventsApiService ($http, $q) {
|
||||
}
|
||||
|
||||
this.state.count = count;
|
||||
|
||||
if (maxCounter > this.state.maxCounter) {
|
||||
this.state.maxCounter = maxCounter;
|
||||
}
|
||||
this.pushMaxCounter(results);
|
||||
|
||||
return rotated;
|
||||
});
|
||||
@ -119,11 +116,8 @@ function JobEventsApiService ($http, $q) {
|
||||
return $http.get(this.endpoint, { params })
|
||||
.then(({ data }) => {
|
||||
const { results } = data;
|
||||
const maxCounter = Math.max(...results.map(({ counter }) => counter));
|
||||
|
||||
if (maxCounter > this.state.maxCounter) {
|
||||
this.state.maxCounter = maxCounter;
|
||||
}
|
||||
this.pushMaxCounter(results);
|
||||
|
||||
return results;
|
||||
});
|
||||
|
||||
@ -22,9 +22,6 @@ const bufferState = [0, 0]; // [length, count]
|
||||
const listeners = [];
|
||||
const rx = [];
|
||||
|
||||
let following = false;
|
||||
let attach = true;
|
||||
|
||||
function bufferInit () {
|
||||
rx.length = 0;
|
||||
|
||||
@ -57,59 +54,91 @@ function bufferEmpty (min, max) {
|
||||
return removed;
|
||||
}
|
||||
|
||||
let attached = false;
|
||||
let noframes = false;
|
||||
let isOnLastPage = false;
|
||||
|
||||
function onFrames (events) {
|
||||
if (!following) {
|
||||
if (noframes) {
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
if (!attached) {
|
||||
const minCounter = Math.min(...events.map(({ counter }) => counter));
|
||||
// attachment range
|
||||
const max = slide.getTailCounter() + 1;
|
||||
const min = Math.max(1, slide.getHeadCounter(), max - 50);
|
||||
|
||||
if (minCounter > max || minCounter < min) {
|
||||
if (minCounter > slide.getTailCounter() + 1) {
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
if (!attach) {
|
||||
return $q.resolve();
|
||||
}
|
||||
attached = true;
|
||||
}
|
||||
|
||||
follow();
|
||||
if (vm.isInFollowMode) {
|
||||
vm.isFollowing = true;
|
||||
}
|
||||
|
||||
const capacity = slide.getCapacity();
|
||||
|
||||
if (capacity <= 0 && !isOnLastPage) {
|
||||
attached = false;
|
||||
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
return slide.popBack(events.length - capacity)
|
||||
.then(() => slide.pushFront(events))
|
||||
.then(() => {
|
||||
scroll.setScrollPosition(scroll.getScrollHeight());
|
||||
if (vm.isFollowing && scroll.isBeyondLowerThreshold()) {
|
||||
scroll.scrollToBottom();
|
||||
}
|
||||
|
||||
return $q.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function first () {
|
||||
unfollow();
|
||||
scroll.pause();
|
||||
unfollow();
|
||||
|
||||
return slide.getFirst()
|
||||
attached = false;
|
||||
noframes = true;
|
||||
isOnLastPage = false;
|
||||
|
||||
slide.getFirst()
|
||||
.then(() => {
|
||||
scroll.resume();
|
||||
noframes = false;
|
||||
|
||||
return $q.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function next () {
|
||||
if (vm.isFollowing) {
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
scroll.pause();
|
||||
|
||||
return slide.getNext()
|
||||
.then(() => {
|
||||
isOnLastPage = slide.isOnLastPage();
|
||||
if (isOnLastPage) {
|
||||
stream.setMissingCounterThreshold(slide.getTailCounter() + 1);
|
||||
if (scroll.isBeyondLowerThreshold()) {
|
||||
scroll.scrollToBottom();
|
||||
follow();
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => scroll.resume());
|
||||
}
|
||||
|
||||
function previous () {
|
||||
unfollow();
|
||||
scroll.pause();
|
||||
|
||||
const initialPosition = scroll.getScrollPosition();
|
||||
isOnLastPage = false;
|
||||
|
||||
return slide.getPrevious()
|
||||
.then(popHeight => {
|
||||
@ -121,6 +150,22 @@ function previous () {
|
||||
.finally(() => scroll.resume());
|
||||
}
|
||||
|
||||
function menuLast () {
|
||||
if (vm.isFollowing) {
|
||||
unfollow();
|
||||
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
if (isOnLastPage) {
|
||||
scroll.scrollToBottom();
|
||||
|
||||
return $q.resolve();
|
||||
}
|
||||
|
||||
return last();
|
||||
}
|
||||
|
||||
function last () {
|
||||
scroll.pause();
|
||||
|
||||
@ -129,7 +174,8 @@ function last () {
|
||||
stream.setMissingCounterThreshold(slide.getTailCounter() + 1);
|
||||
scroll.setScrollPosition(scroll.getScrollHeight());
|
||||
|
||||
attach = true;
|
||||
isOnLastPage = true;
|
||||
follow();
|
||||
scroll.resume();
|
||||
|
||||
return $q.resolve();
|
||||
@ -141,28 +187,21 @@ function down () {
|
||||
}
|
||||
|
||||
function up () {
|
||||
if (following) {
|
||||
unfollow();
|
||||
} else {
|
||||
scroll.moveUp();
|
||||
}
|
||||
scroll.moveUp();
|
||||
}
|
||||
|
||||
function follow () {
|
||||
scroll.pause();
|
||||
scroll.hide();
|
||||
isOnLastPage = slide.isOnLastPage();
|
||||
|
||||
following = true;
|
||||
vm.isFollowing = following;
|
||||
if (resource.model.get('event_processing_finished')) return;
|
||||
if (!isOnLastPage) return;
|
||||
|
||||
vm.isInFollowMode = true;
|
||||
}
|
||||
|
||||
function unfollow () {
|
||||
attach = false;
|
||||
following = false;
|
||||
vm.isFollowing = following;
|
||||
|
||||
scroll.unhide();
|
||||
scroll.resume();
|
||||
vm.isInFollowMode = false;
|
||||
vm.isFollowing = false;
|
||||
}
|
||||
|
||||
function togglePanelExpand () {
|
||||
@ -276,6 +315,13 @@ function reloadState (params) {
|
||||
return $state.transitionTo($state.current, params, { inherit: false, location: 'replace' });
|
||||
}
|
||||
|
||||
function getMaxCounter () {
|
||||
const apiMax = resource.events.getMaxCounter();
|
||||
const wsMax = stream.getMaxCounter();
|
||||
|
||||
return Math.max(apiMax, wsMax);
|
||||
}
|
||||
|
||||
function OutputIndexController (
|
||||
_$compile_,
|
||||
_$q_,
|
||||
@ -318,9 +364,10 @@ function OutputIndexController (
|
||||
vm.togglePanelExpand = togglePanelExpand;
|
||||
|
||||
// Stdout Navigation
|
||||
vm.menu = { last, first, down, up };
|
||||
vm.menu = { last: menuLast, first, down, up };
|
||||
vm.isMenuExpanded = true;
|
||||
vm.isFollowing = following;
|
||||
vm.isFollowing = false;
|
||||
vm.isInFollowMode = false;
|
||||
vm.toggleMenuExpand = toggleMenuExpand;
|
||||
vm.toggleLineExpand = toggleLineExpand;
|
||||
vm.showHostDetails = showHostDetails;
|
||||
@ -330,10 +377,21 @@ function OutputIndexController (
|
||||
bufferInit();
|
||||
|
||||
status.init(resource);
|
||||
slide.init(render, resource.events, scroll);
|
||||
|
||||
slide.init(render, resource.events, scroll, { getMaxCounter });
|
||||
render.init({ compile, toggles: vm.toggleLineEnabled });
|
||||
scroll.init({ previous, next });
|
||||
|
||||
scroll.init({
|
||||
next,
|
||||
previous,
|
||||
onLeaveLower () {
|
||||
unfollow();
|
||||
return $q.resolve();
|
||||
},
|
||||
onEnterLower () {
|
||||
follow();
|
||||
return $q.resolve();
|
||||
},
|
||||
});
|
||||
|
||||
stream.init({
|
||||
bufferAdd,
|
||||
|
||||
@ -24,10 +24,9 @@
|
||||
<i class="at-Stdout-menuIcon fa" ng-if="vm.toggleLineEnabled"
|
||||
ng-class="{ 'fa-minus': vm.isMenuExpanded, 'fa-plus': !vm.isMenuExpanded }"></i>
|
||||
</div>
|
||||
|
||||
<div class="pull-right" ng-click="vm.menu.last()">
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-down"
|
||||
ng-class=" { 'at-Stdout-menuIcon--active': vm.menu.isLocked }"></i>
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-down"
|
||||
ng-class=" { 'at-Stdout-menuIconStackTop--active': false }"></i>
|
||||
</div>
|
||||
<div class="pull-right" ng-click="vm.menu.first()">
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-up"></i>
|
||||
@ -36,8 +35,7 @@
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-down"></i>
|
||||
</div>
|
||||
<div class="pull-right" ng-click="vm.menu.up()">
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-up"
|
||||
ng-class=" { 'at-Stdout-menuIcon--active': vm.isFollowing }"></i>
|
||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-up"></i>
|
||||
</div>
|
||||
|
||||
<div class="at-u-clear"></div>
|
||||
@ -48,15 +46,6 @@
|
||||
<div id="atStdoutResultTable"></div>
|
||||
<div class="at-Stdout-borderFooter"></div>
|
||||
</div>
|
||||
|
||||
<div ng-show="vm.menu.showBackToTop" class="at-Stdout-menuBottom">
|
||||
<div class="at-Stdout-menuIconGroup" ng-click="vm.menu.home()">
|
||||
<p class="pull-left"><i class="fa fa-angle-double-up"></i></p>
|
||||
<p class="pull-right">{{:: vm.strings.get('stdout.BACK_TO_TOP') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="at-u-clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
</at-panel>
|
||||
</div>
|
||||
|
||||
@ -235,6 +235,7 @@ function PageService ($q) {
|
||||
})
|
||||
.then(() => this.getNext());
|
||||
|
||||
this.isOnLastPage = () => this.api.getLastPageNumber() === this.state.tail;
|
||||
this.getRecordCount = () => Object.keys(this.records).length;
|
||||
this.getTailCounter = () => this.state.tail;
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
} from './constants';
|
||||
|
||||
function JobScrollService ($q, $timeout) {
|
||||
this.init = ({ next, previous }) => {
|
||||
this.init = ({ next, previous, onLeaveLower, onEnterLower }) => {
|
||||
this.el = $(OUTPUT_ELEMENT_CONTAINER);
|
||||
this.timer = null;
|
||||
|
||||
@ -15,18 +15,23 @@ function JobScrollService ($q, $timeout) {
|
||||
current: 0
|
||||
};
|
||||
|
||||
this.threshold = {
|
||||
previous: 0,
|
||||
current: 0,
|
||||
};
|
||||
|
||||
this.hooks = {
|
||||
next,
|
||||
previous,
|
||||
isAtRest: () => $q.resolve()
|
||||
onLeaveLower,
|
||||
onEnterLower,
|
||||
};
|
||||
|
||||
this.state = {
|
||||
hidden: false,
|
||||
paused: false,
|
||||
top: true,
|
||||
};
|
||||
|
||||
this.chain = $q.resolve();
|
||||
this.el.scroll(this.listen);
|
||||
};
|
||||
|
||||
@ -42,70 +47,82 @@ function JobScrollService ($q, $timeout) {
|
||||
this.timer = $timeout(this.register, OUTPUT_SCROLL_DELAY);
|
||||
};
|
||||
|
||||
this.isBeyondThreshold = () => {
|
||||
const position = this.getScrollPosition();
|
||||
const viewport = this.getScrollHeight() - this.getViewableHeight();
|
||||
const threshold = position / viewport;
|
||||
|
||||
return (1 - threshold) < OUTPUT_SCROLL_THRESHOLD;
|
||||
};
|
||||
|
||||
this.register = () => {
|
||||
this.pause();
|
||||
|
||||
const current = this.getScrollPosition();
|
||||
const downward = current > this.position.previous;
|
||||
const position = this.getScrollPosition();
|
||||
const viewport = this.getScrollHeight() - this.getViewableHeight();
|
||||
|
||||
let promise;
|
||||
const threshold = position / viewport;
|
||||
const downward = position > this.position.previous;
|
||||
|
||||
if (downward && this.isBeyondThreshold(downward, current)) {
|
||||
promise = this.hooks.next;
|
||||
} else if (!downward && this.isBeyondThreshold(downward, current)) {
|
||||
promise = this.hooks.previous;
|
||||
const isBeyondUpperThreshold = threshold < OUTPUT_SCROLL_THRESHOLD;
|
||||
const isBeyondLowerThreshold = (1 - threshold) < OUTPUT_SCROLL_THRESHOLD;
|
||||
|
||||
const wasBeyondUpperThreshold = this.threshold.previous < OUTPUT_SCROLL_THRESHOLD;
|
||||
const wasBeyondLowerThreshold = (1 - this.threshold.previous) < OUTPUT_SCROLL_THRESHOLD;
|
||||
|
||||
const transitions = [];
|
||||
|
||||
if (position <= 0 || (isBeyondUpperThreshold && !wasBeyondUpperThreshold)) {
|
||||
transitions.push(this.hooks.previous);
|
||||
}
|
||||
|
||||
if (!promise) {
|
||||
this.setScrollPosition(current);
|
||||
this.isAtRest();
|
||||
this.resume();
|
||||
|
||||
return $q.resolve();
|
||||
if (!isBeyondLowerThreshold && wasBeyondLowerThreshold) {
|
||||
transitions.push(this.hooks.onLeaveLower);
|
||||
}
|
||||
|
||||
return promise()
|
||||
if (isBeyondLowerThreshold && !wasBeyondLowerThreshold) {
|
||||
transitions.push(this.hooks.onEnterLower);
|
||||
transitions.push(this.hooks.next);
|
||||
} else if (threshold >= 1) {
|
||||
transitions.push(this.hooks.next);
|
||||
}
|
||||
|
||||
if (!downward) {
|
||||
transitions.reverse();
|
||||
}
|
||||
|
||||
this.position.current = position;
|
||||
this.threshold.current = threshold;
|
||||
|
||||
transitions.forEach(promise => {
|
||||
this.chain = this.chain.then(() => promise());
|
||||
});
|
||||
|
||||
return this.chain
|
||||
.then(() => {
|
||||
this.setScrollPosition(this.getScrollPosition());
|
||||
this.isAtRest();
|
||||
this.resume();
|
||||
this.setScrollPosition(this.getScrollPosition());
|
||||
|
||||
return $q.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
this.isBeyondThreshold = (downward, current) => {
|
||||
const height = this.getScrollHeight();
|
||||
|
||||
if (downward) {
|
||||
current += this.getViewableHeight();
|
||||
|
||||
if (current >= height || ((height - current) / height) < OUTPUT_SCROLL_THRESHOLD) {
|
||||
return true;
|
||||
}
|
||||
} else if (current <= 0 || (current / height) < OUTPUT_SCROLL_THRESHOLD) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Move scroll position up by one page of visible content.
|
||||
*/
|
||||
this.moveUp = () => {
|
||||
const top = this.getScrollPosition();
|
||||
const height = this.getViewableHeight();
|
||||
const position = this.getScrollPosition() - this.getViewableHeight();
|
||||
|
||||
this.setScrollPosition(top - height);
|
||||
this.setScrollPosition(position);
|
||||
};
|
||||
|
||||
/**
|
||||
* Move scroll position down by one page of visible content.
|
||||
*/
|
||||
this.moveDown = () => {
|
||||
const top = this.getScrollPosition();
|
||||
const height = this.getViewableHeight();
|
||||
const position = this.getScrollPosition() + this.getViewableHeight();
|
||||
|
||||
this.setScrollPosition(top + height);
|
||||
this.setScrollPosition(position);
|
||||
};
|
||||
|
||||
this.getScrollHeight = () => this.el[0].scrollHeight;
|
||||
@ -119,33 +136,27 @@ function JobScrollService ($q, $timeout) {
|
||||
this.getScrollPosition = () => this.el[0].scrollTop;
|
||||
|
||||
this.setScrollPosition = position => {
|
||||
const viewport = this.getScrollHeight() - this.getViewableHeight();
|
||||
|
||||
this.position.previous = this.position.current;
|
||||
this.threshold.previous = this.position.previous / viewport;
|
||||
this.position.current = position;
|
||||
|
||||
this.el[0].scrollTop = position;
|
||||
this.isAtRest();
|
||||
};
|
||||
|
||||
this.resetScrollPosition = () => {
|
||||
this.threshold.previous = 0;
|
||||
this.position.previous = 0;
|
||||
this.position.current = 0;
|
||||
|
||||
this.el[0].scrollTop = 0;
|
||||
this.isAtRest();
|
||||
};
|
||||
|
||||
this.scrollToBottom = () => {
|
||||
this.setScrollPosition(this.getScrollHeight());
|
||||
};
|
||||
|
||||
this.isAtRest = () => {
|
||||
if (this.position.current === 0 && !this.state.top) {
|
||||
this.state.top = true;
|
||||
this.hooks.isAtRest(true);
|
||||
} else if (this.position.current > 0 && this.state.top) {
|
||||
this.state.top = false;
|
||||
this.hooks.isAtRest(false);
|
||||
}
|
||||
};
|
||||
|
||||
this.resume = () => {
|
||||
this.state.paused = false;
|
||||
};
|
||||
@ -154,32 +165,8 @@ function JobScrollService ($q, $timeout) {
|
||||
this.state.paused = true;
|
||||
};
|
||||
|
||||
this.isPaused = () => this.state.paused;
|
||||
|
||||
this.lock = () => {
|
||||
this.state.locked = true;
|
||||
};
|
||||
|
||||
this.unlock = () => {
|
||||
this.state.locked = false;
|
||||
};
|
||||
|
||||
this.hide = () => {
|
||||
if (!this.state.hidden) {
|
||||
this.el.css('overflow', 'hidden');
|
||||
this.state.hidden = true;
|
||||
}
|
||||
};
|
||||
|
||||
this.unhide = () => {
|
||||
if (this.state.hidden) {
|
||||
this.el.css('overflow', 'auto');
|
||||
this.state.hidden = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.isLocked = () => this.state.locked;
|
||||
this.isMissing = () => $(OUTPUT_ELEMENT_TBODY)[0].clientHeight < this.getViewableHeight();
|
||||
this.isPaused = () => this.state.paused;
|
||||
}
|
||||
|
||||
JobScrollService.$inject = ['$q', '$timeout'];
|
||||
|
||||
@ -77,15 +77,15 @@ function getBoundedRange (range, other) {
|
||||
}
|
||||
|
||||
function SlidingWindowService ($q) {
|
||||
this.init = (storage, api, { getScrollHeight }) => {
|
||||
this.init = (storage, api, { getScrollHeight }, { getMaxCounter }) => {
|
||||
const { prepend, append, shift, pop, deleteRecord } = storage;
|
||||
const { getMaxCounter, getRange, getFirst, getLast } = api;
|
||||
const { getRange, getFirst, getLast } = api;
|
||||
|
||||
this.api = {
|
||||
getMaxCounter,
|
||||
getRange,
|
||||
getFirst,
|
||||
getLast,
|
||||
getMaxCounter,
|
||||
};
|
||||
|
||||
this.storage = {
|
||||
@ -352,13 +352,8 @@ function SlidingWindowService ($q) {
|
||||
return Number.isFinite(head) ? head : 0;
|
||||
};
|
||||
|
||||
this.getMaxCounter = () => {
|
||||
const counter = this.api.getMaxCounter();
|
||||
const tail = this.getTailCounter();
|
||||
|
||||
return Number.isFinite(counter) ? Math.max(tail, counter) : tail;
|
||||
};
|
||||
|
||||
this.isOnLastPage = () => this.getTailCounter() >= (this.getMaxCounter() - OUTPUT_PAGE_SIZE);
|
||||
this.getMaxCounter = () => this.api.getMaxCounter();
|
||||
this.getRange = () => [this.getHeadCounter(), this.getTailCounter()];
|
||||
this.getRecordCount = () => Object.keys(this.records).length;
|
||||
this.getCapacity = () => OUTPUT_EVENT_LIMIT - this.getRecordCount();
|
||||
|
||||
@ -160,6 +160,8 @@ function OutputStream ($q) {
|
||||
this.counters.ready.length = 0;
|
||||
return $q.resolve();
|
||||
});
|
||||
|
||||
this.getMaxCounter = () => this.counters.max;
|
||||
}
|
||||
|
||||
OutputStream.$inject = ['$q'];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user