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