mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
infinitescroll
This commit is contained in:
parent
27febb599c
commit
61fb4a9c6b
5 changed files with 144 additions and 28 deletions
|
@ -118,6 +118,7 @@ function loadForm(context, user, userSettings) {
|
|||
context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
||||
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
|
||||
context.querySelector('#infscroll').checked = userSettings.enableInfiniteScroll();
|
||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
||||
|
||||
|
@ -158,6 +159,7 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
|
|||
userSettingsInstance.screensaverTime(context.querySelector('#txtScreensaverTime').value);
|
||||
|
||||
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
||||
userSettingsInstance.enableInfiniteScroll(context.querySelector('#infscroll').checked);
|
||||
|
||||
userSettingsInstance.maxDaysForNextUp(context.querySelector('#txtMaxDaysForNextUp').value);
|
||||
userSettingsInstance.enableRewatchingInNextUp(context.querySelector('#chkRewatchingNextUp').checked);
|
||||
|
|
|
@ -239,6 +239,14 @@
|
|||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="infscroll" />
|
||||
<span>${infinitescroll}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${infinitescroll}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||
|
|
|
@ -81,6 +81,7 @@ export default function (view, params, tabContent) {
|
|||
};
|
||||
|
||||
const reloadItems = () => {
|
||||
if (isLoading) return;
|
||||
loading.show();
|
||||
isLoading = true;
|
||||
const query = getQuery();
|
||||
|
@ -109,7 +110,9 @@ export default function (view, params, tabContent) {
|
|||
reloadItems();
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
if (!userSettings.enableInfiniteScroll()) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
this.alphaPicker?.updateControls(query);
|
||||
let html;
|
||||
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||
|
@ -154,24 +157,51 @@ export default function (view, params, tabContent) {
|
|||
});
|
||||
}
|
||||
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
if (!userSettings.enableInfiniteScroll()) {
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
|
||||
for (const elem of elems) {
|
||||
elem.innerHTML = pagingHtml;
|
||||
}
|
||||
for (const elem of elems) {
|
||||
elem.innerHTML = pagingHtml;
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onNextPageClick);
|
||||
}
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onNextPageClick);
|
||||
};
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onPreviousPageClick);
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onPreviousPageClick);
|
||||
}
|
||||
} else {
|
||||
hasMoreitems = true;
|
||||
// Check if we need to load more items
|
||||
if (result.Items.length >= query.Limit) {
|
||||
query.StartIndex += query.Limit;
|
||||
} else if (query.NameStartsWith !== undefined) {
|
||||
// no more items with the alphaPicker/NameStartsWith selection.
|
||||
// increment ascii letter code and search with next letter
|
||||
const nextletter = String.fromCharCode(query.NameStartsWith.charCodeAt(0) + 1);
|
||||
// check if ascii code is smaler or equal to Z else disable loading more items
|
||||
if (nextletter.charCodeAt(0) <= 90) {
|
||||
query.NameStartsWith = nextletter;
|
||||
//reset start index for new letter
|
||||
query.StartIndex = 0;
|
||||
} else {
|
||||
hasMoreitems = false;
|
||||
}
|
||||
} else {
|
||||
//if not searching with NameStartsWith set hasMoreitems false if no more items are found
|
||||
hasMoreitems = false;
|
||||
}
|
||||
}
|
||||
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
itemsContainer.innerHTML = html;
|
||||
if (userSettings.enableInfiniteScroll()) {
|
||||
itemsContainer.innerHTML += html;
|
||||
} else {
|
||||
itemsContainer.innerHTML = html;
|
||||
}
|
||||
imageLoader.lazyChildren(itemsContainer);
|
||||
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
||||
loading.hide();
|
||||
|
@ -185,7 +215,8 @@ export default function (view, params, tabContent) {
|
|||
|
||||
let pageData;
|
||||
let isLoading = false;
|
||||
|
||||
let hasMoreitems = true;
|
||||
const scrollController = new AbortController();
|
||||
this.showFilterMenu = function () {
|
||||
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
||||
const filterDialog = new FilterDialog({
|
||||
|
@ -221,6 +252,7 @@ export default function (view, params, tabContent) {
|
|||
delete query.NameLessThan;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
itemsContainer.innerHTML = '';
|
||||
reloadItems();
|
||||
});
|
||||
|
||||
|
@ -284,6 +316,20 @@ export default function (view, params, tabContent) {
|
|||
reloadItems();
|
||||
});
|
||||
|
||||
if (userSettings.enableInfiniteScroll()) {
|
||||
document.addEventListener('viewshow', () => {
|
||||
// Stop the scroll event listener on view change
|
||||
scrollController.abort();
|
||||
}, { signal: scrollController.signal });
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
// check if tabelement is active else dont run reloaditems
|
||||
if (window.scrollY >= document.documentElement.scrollHeight - 1000 && (!isLoading && hasMoreitems) && tabElement.classList.contains('is-active')) {
|
||||
reloadItems();
|
||||
}
|
||||
}, { signal: scrollController.signal });
|
||||
}
|
||||
|
||||
tabElement.querySelector('.btnPlayAll').addEventListener('click', playAll);
|
||||
tabElement.querySelector('.btnShuffle').addEventListener('click', shuffle);
|
||||
};
|
||||
|
|
|
@ -65,6 +65,7 @@ export default function (view, params, tabContent, options) {
|
|||
};
|
||||
|
||||
const reloadItems = () => {
|
||||
if (isLoading) return;
|
||||
loading.show();
|
||||
isLoading = true;
|
||||
const query = getQuery();
|
||||
|
@ -96,7 +97,9 @@ export default function (view, params, tabContent, options) {
|
|||
reloadItems();
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
if (!userSettings.enableInfiniteScroll()) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
this.alphaPicker?.updateControls(query);
|
||||
let html;
|
||||
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||
|
@ -136,24 +139,52 @@ export default function (view, params, tabContent, options) {
|
|||
overlayPlayButton: true
|
||||
});
|
||||
}
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].innerHTML = pagingHtml;
|
||||
}
|
||||
if (!userSettings.enableInfiniteScroll()) {
|
||||
let elems = tabContent.querySelectorAll('.paging');
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onNextPageClick);
|
||||
}
|
||||
for (const elem of elems) {
|
||||
elem.innerHTML = pagingHtml;
|
||||
}
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (let i = 0, length = elems.length; i < length; i++) {
|
||||
elems[i].addEventListener('click', onPreviousPageClick);
|
||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onNextPageClick);
|
||||
};
|
||||
|
||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||
for (const elem of elems) {
|
||||
elem.addEventListener('click', onPreviousPageClick);
|
||||
}
|
||||
} else {
|
||||
hasMoreitems = true;
|
||||
// Check if we need to load more items
|
||||
if (result.Items.length >= query.Limit) {
|
||||
query.StartIndex += query.Limit;
|
||||
} else if (query.NameStartsWith !== undefined) {
|
||||
// no more items with the alphaPicker/NameStartsWith selection.
|
||||
// increment ascii letter code and search with next letter
|
||||
const nextletter = String.fromCharCode(query.NameStartsWith.charCodeAt(0) + 1);
|
||||
// check if ascii code is smaller or equal to Z else disable loading more items
|
||||
if (nextletter.charCodeAt(0) <= 90) {
|
||||
query.NameStartsWith = nextletter;
|
||||
//reset start index for new letter
|
||||
query.StartIndex = 0;
|
||||
} else {
|
||||
hasMoreitems = false;
|
||||
}
|
||||
} else {
|
||||
//if not searching with NameStartsWith set hasMoreitems false if no more items are found
|
||||
hasMoreitems = false;
|
||||
}
|
||||
}
|
||||
|
||||
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||
itemsContainer.innerHTML = html;
|
||||
if (userSettings.enableInfiniteScroll()) {
|
||||
itemsContainer.innerHTML += html;
|
||||
} else {
|
||||
itemsContainer.innerHTML = html;
|
||||
}
|
||||
imageLoader.lazyChildren(itemsContainer);
|
||||
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
||||
loading.hide();
|
||||
|
@ -167,7 +198,8 @@ export default function (view, params, tabContent, options) {
|
|||
|
||||
const data = {};
|
||||
let isLoading = false;
|
||||
|
||||
let hasMoreitems = true;
|
||||
const scrollController = new AbortController();
|
||||
this.showFilterMenu = function () {
|
||||
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
||||
const filterDialog = new FilterDialog({
|
||||
|
@ -202,6 +234,7 @@ export default function (view, params, tabContent, options) {
|
|||
delete query.NameLessThan;
|
||||
}
|
||||
query.StartIndex = 0;
|
||||
itemsContainer.innerHTML = ''; // Clear the existing items
|
||||
reloadItems();
|
||||
});
|
||||
this.alphaPicker = new AlphaPicker({
|
||||
|
@ -228,6 +261,19 @@ export default function (view, params, tabContent, options) {
|
|||
onViewStyleChange();
|
||||
reloadItems();
|
||||
});
|
||||
if (userSettings.enableInfiniteScroll()) {
|
||||
document.addEventListener('viewshow', () => {
|
||||
// Stop the scroll event listener on view change
|
||||
scrollController.abort();
|
||||
}, { signal: scrollController.signal });
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
// check if tabelement is active else dont run reloaditems
|
||||
if (window.scrollY >= document.documentElement.scrollHeight - 1000 && (!isLoading && hasMoreitems) && tabElement.classList.contains('is-active')) {
|
||||
reloadItems();
|
||||
}
|
||||
}, { signal: scrollController.signal });
|
||||
}
|
||||
};
|
||||
|
||||
initPage(tabContent);
|
||||
|
|
|
@ -483,6 +483,19 @@ export class UserSettings {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set infinite scroll .
|
||||
* @param {boolean|undefined} [val] - enable infinite scroll
|
||||
* @return {bool} infinite scroll enable.
|
||||
*/
|
||||
enableInfiniteScroll(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('enableInfiniteScroll', val, false);
|
||||
}
|
||||
|
||||
return toBoolean(this.get('enableInfiniteScroll', false), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set max days for next up list.
|
||||
* @param {number|undefined} [val] - Max days for next up.
|
||||
|
@ -703,6 +716,7 @@ export const setSubtitleAppearanceSettings = currentSettings.setSubtitleAppearan
|
|||
export const getComicsPlayerSettings = currentSettings.getComicsPlayerSettings.bind(currentSettings);
|
||||
export const setComicsPlayerSettings = currentSettings.setComicsPlayerSettings.bind(currentSettings);
|
||||
export const setFilter = currentSettings.setFilter.bind(currentSettings);
|
||||
export const enableInfiniteScroll = currentSettings.enableInfiniteScroll.bind(currentSettings);
|
||||
export const getFilter = currentSettings.getFilter.bind(currentSettings);
|
||||
export const customCss = currentSettings.customCss.bind(currentSettings);
|
||||
export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue