You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nodebb/public/src/client/infinitescroll.js

125 lines
3.3 KiB
JavaScript

'use strict';
define('forum/infinitescroll', ['hooks', 'alerts'], function (hooks, alerts) {
const scroll = {};
let callback;
let previousScrollTop = 0;
let loadingMore = false;
let container;
let scrollTimeout = 0;
scroll.init = function (el, cb) {
const $body = $('body');
if (typeof el === 'function') {
callback = el;
container = $body;
} else {
callback = cb;
container = el || $body;
}
previousScrollTop = $(window).scrollTop();
$(window).off('scroll', startScrollTimeout).on('scroll', startScrollTimeout);
if ($body.height() <= $(window).height()) {
callback(1);
}
};
function startScrollTimeout() {
if (scrollTimeout) {
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(function () {
scrollTimeout = 0;
onScroll();
}, 60);
}
function onScroll() {
const bsEnv = utils.findBootstrapEnvironment();
const mobileComposerOpen = (bsEnv === 'xs' || bsEnv === 'sm') && $('html').hasClass('composing');
if (loadingMore || mobileComposerOpen || app.flags._glance) {
return;
}
const currentScrollTop = $(window).scrollTop();
const wh = $(window).height();
const viewportHeight = container.height() - wh;
const offsetTop = container.offset() ? container.offset().top : 0;
const scrollPercent = 100 * (currentScrollTop - offsetTop) / (viewportHeight <= 0 ? wh : viewportHeight);
const top = 15;
const bottom = 85;
const direction = currentScrollTop > previousScrollTop ? 1 : -1;
if (scrollPercent < top && currentScrollTop < previousScrollTop) {
callback(direction);
} else if (scrollPercent > bottom && currentScrollTop > previousScrollTop) {
callback(direction);
} else if (scrollPercent < 0 && direction > 0 && viewportHeight < 0) {
callback(direction);
}
previousScrollTop = currentScrollTop;
}
scroll.loadMore = function (method, data, callback) {
if (loadingMore) {
return;
}
loadingMore = true;
const hookData = { method: method, data: data };
hooks.fire('action:infinitescroll.loadmore', hookData);
socket.emit(hookData.method, hookData.data, function (err, data) {
if (err) {
loadingMore = false;
return alerts.error(err);
}
callback(data, function () {
loadingMore = false;
});
});
};
scroll.loadMoreXhr = function (data, callback) {
if (loadingMore) {
return;
}
loadingMore = true;
const url = config.relative_path + '/api' + location.pathname.replace(new RegExp('^' + config.relative_path), '');
const hookData = { url: url, data: data };
hooks.fire('action:infinitescroll.loadmore.xhr', hookData);
$.get(url, data, function (data) {
callback(data, function () {
loadingMore = false;
});
}).fail(function (jqXHR) {
loadingMore = false;
alerts.error(String(jqXHR.responseJSON || '[[error:no-connection]]'));
});
};
scroll.removeExtra = function (els, direction, count) {
let removedEls = $();
if (els.length <= count) {
return removedEls;
}
const removeCount = els.length - count;
if (direction > 0) {
const height = $(document).height();
const scrollTop = $(window).scrollTop();
removedEls = els.slice(0, removeCount).remove();
$(window).scrollTop(scrollTop + ($(document).height() - height));
} else {
removedEls = els.slice(els.length - removeCount).remove();
}
return removedEls;
};
return scroll;
});