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('#chkThemeVideo').checked = userSettings.enableThemeVideos();
|
||||||
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
context.querySelector('#chkFadein').checked = userSettings.enableFastFadein();
|
||||||
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
|
context.querySelector('#chkBlurhash').checked = userSettings.enableBlurhash();
|
||||||
|
context.querySelector('#infscroll').checked = userSettings.enableInfiniteScroll();
|
||||||
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops();
|
||||||
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
context.querySelector('#chkDetailsBanner').checked = userSettings.detailsBanner();
|
||||||
|
|
||||||
|
@ -158,6 +159,7 @@ function saveUser(context, user, userSettingsInstance, apiClient) {
|
||||||
userSettingsInstance.screensaverTime(context.querySelector('#txtScreensaverTime').value);
|
userSettingsInstance.screensaverTime(context.querySelector('#txtScreensaverTime').value);
|
||||||
|
|
||||||
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value);
|
||||||
|
userSettingsInstance.enableInfiniteScroll(context.querySelector('#infscroll').checked);
|
||||||
|
|
||||||
userSettingsInstance.maxDaysForNextUp(context.querySelector('#txtMaxDaysForNextUp').value);
|
userSettingsInstance.maxDaysForNextUp(context.querySelector('#txtMaxDaysForNextUp').value);
|
||||||
userSettingsInstance.enableRewatchingInNextUp(context.querySelector('#chkRewatchingNextUp').checked);
|
userSettingsInstance.enableRewatchingInNextUp(context.querySelector('#chkRewatchingNextUp').checked);
|
||||||
|
|
|
@ -239,6 +239,14 @@
|
||||||
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
<div class="fieldDescription">${LabelLibraryPageSizeHelp}</div>
|
||||||
</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">
|
<div class="checkboxContainer checkboxContainer-withDescription fldBackdrops">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
<input type="checkbox" is="emby-checkbox" id="chkBackdrops" />
|
||||||
|
|
|
@ -81,6 +81,7 @@ export default function (view, params, tabContent) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const reloadItems = () => {
|
const reloadItems = () => {
|
||||||
|
if (isLoading) return;
|
||||||
loading.show();
|
loading.show();
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
const query = getQuery();
|
const query = getQuery();
|
||||||
|
@ -109,7 +110,9 @@ export default function (view, params, tabContent) {
|
||||||
reloadItems();
|
reloadItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
if (!userSettings.enableInfiniteScroll()) {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
this.alphaPicker?.updateControls(query);
|
this.alphaPicker?.updateControls(query);
|
||||||
let html;
|
let html;
|
||||||
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
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) {
|
for (const elem of elems) {
|
||||||
elem.innerHTML = pagingHtml;
|
elem.innerHTML = pagingHtml;
|
||||||
}
|
}
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||||
for (const elem of elems) {
|
for (const elem of elems) {
|
||||||
elem.addEventListener('click', onNextPageClick);
|
elem.addEventListener('click', onNextPageClick);
|
||||||
}
|
};
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
||||||
for (const elem of elems) {
|
for (const elem of elems) {
|
||||||
elem.addEventListener('click', onPreviousPageClick);
|
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');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
itemsContainer.innerHTML = html;
|
if (userSettings.enableInfiniteScroll()) {
|
||||||
|
itemsContainer.innerHTML += html;
|
||||||
|
} else {
|
||||||
|
itemsContainer.innerHTML = html;
|
||||||
|
}
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
|
@ -185,7 +215,8 @@ export default function (view, params, tabContent) {
|
||||||
|
|
||||||
let pageData;
|
let pageData;
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
|
let hasMoreitems = true;
|
||||||
|
const scrollController = new AbortController();
|
||||||
this.showFilterMenu = function () {
|
this.showFilterMenu = function () {
|
||||||
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
||||||
const filterDialog = new FilterDialog({
|
const filterDialog = new FilterDialog({
|
||||||
|
@ -221,6 +252,7 @@ export default function (view, params, tabContent) {
|
||||||
delete query.NameLessThan;
|
delete query.NameLessThan;
|
||||||
}
|
}
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
|
itemsContainer.innerHTML = '';
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -284,6 +316,20 @@ export default function (view, params, tabContent) {
|
||||||
reloadItems();
|
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('.btnPlayAll').addEventListener('click', playAll);
|
||||||
tabElement.querySelector('.btnShuffle').addEventListener('click', shuffle);
|
tabElement.querySelector('.btnShuffle').addEventListener('click', shuffle);
|
||||||
};
|
};
|
||||||
|
|
|
@ -65,6 +65,7 @@ export default function (view, params, tabContent, options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const reloadItems = () => {
|
const reloadItems = () => {
|
||||||
|
if (isLoading) return;
|
||||||
loading.show();
|
loading.show();
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
const query = getQuery();
|
const query = getQuery();
|
||||||
|
@ -96,7 +97,9 @@ export default function (view, params, tabContent, options) {
|
||||||
reloadItems();
|
reloadItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.scrollTo(0, 0);
|
if (!userSettings.enableInfiniteScroll()) {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
}
|
||||||
this.alphaPicker?.updateControls(query);
|
this.alphaPicker?.updateControls(query);
|
||||||
let html;
|
let html;
|
||||||
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
const pagingHtml = libraryBrowser.getQueryPagingHtml({
|
||||||
|
@ -136,24 +139,52 @@ export default function (view, params, tabContent, options) {
|
||||||
overlayPlayButton: true
|
overlayPlayButton: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let elems = tabContent.querySelectorAll('.paging');
|
|
||||||
|
|
||||||
for (let i = 0, length = elems.length; i < length; i++) {
|
if (!userSettings.enableInfiniteScroll()) {
|
||||||
elems[i].innerHTML = pagingHtml;
|
let elems = tabContent.querySelectorAll('.paging');
|
||||||
}
|
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnNextPage');
|
for (const elem of elems) {
|
||||||
for (let i = 0, length = elems.length; i < length; i++) {
|
elem.innerHTML = pagingHtml;
|
||||||
elems[i].addEventListener('click', onNextPageClick);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
elems = tabContent.querySelectorAll('.btnPreviousPage');
|
elems = tabContent.querySelectorAll('.btnNextPage');
|
||||||
for (let i = 0, length = elems.length; i < length; i++) {
|
for (const elem of elems) {
|
||||||
elems[i].addEventListener('click', onPreviousPageClick);
|
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');
|
const itemsContainer = tabContent.querySelector('.itemsContainer');
|
||||||
itemsContainer.innerHTML = html;
|
if (userSettings.enableInfiniteScroll()) {
|
||||||
|
itemsContainer.innerHTML += html;
|
||||||
|
} else {
|
||||||
|
itemsContainer.innerHTML = html;
|
||||||
|
}
|
||||||
imageLoader.lazyChildren(itemsContainer);
|
imageLoader.lazyChildren(itemsContainer);
|
||||||
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
userSettings.saveQuerySettings(getSavedQueryKey(), query);
|
||||||
loading.hide();
|
loading.hide();
|
||||||
|
@ -167,7 +198,8 @@ export default function (view, params, tabContent, options) {
|
||||||
|
|
||||||
const data = {};
|
const data = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
|
let hasMoreitems = true;
|
||||||
|
const scrollController = new AbortController();
|
||||||
this.showFilterMenu = function () {
|
this.showFilterMenu = function () {
|
||||||
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
import('../../components/filterdialog/filterdialog').then(({ default: FilterDialog }) => {
|
||||||
const filterDialog = new FilterDialog({
|
const filterDialog = new FilterDialog({
|
||||||
|
@ -202,6 +234,7 @@ export default function (view, params, tabContent, options) {
|
||||||
delete query.NameLessThan;
|
delete query.NameLessThan;
|
||||||
}
|
}
|
||||||
query.StartIndex = 0;
|
query.StartIndex = 0;
|
||||||
|
itemsContainer.innerHTML = ''; // Clear the existing items
|
||||||
reloadItems();
|
reloadItems();
|
||||||
});
|
});
|
||||||
this.alphaPicker = new AlphaPicker({
|
this.alphaPicker = new AlphaPicker({
|
||||||
|
@ -228,6 +261,19 @@ export default function (view, params, tabContent, options) {
|
||||||
onViewStyleChange();
|
onViewStyleChange();
|
||||||
reloadItems();
|
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);
|
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.
|
* Get or set max days for next up list.
|
||||||
* @param {number|undefined} [val] - Max days for next up.
|
* @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 getComicsPlayerSettings = currentSettings.getComicsPlayerSettings.bind(currentSettings);
|
||||||
export const setComicsPlayerSettings = currentSettings.setComicsPlayerSettings.bind(currentSettings);
|
export const setComicsPlayerSettings = currentSettings.setComicsPlayerSettings.bind(currentSettings);
|
||||||
export const setFilter = currentSettings.setFilter.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 getFilter = currentSettings.getFilter.bind(currentSettings);
|
||||||
export const customCss = currentSettings.customCss.bind(currentSettings);
|
export const customCss = currentSettings.customCss.bind(currentSettings);
|
||||||
export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings);
|
export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue