diff --git a/dist/plex-meets-homeassistant.js b/dist/plex-meets-homeassistant.js index fe5d912..4fb966d 100644 --- a/dist/plex-meets-homeassistant.js +++ b/dist/plex-meets-homeassistant.js @@ -19014,6 +19014,16 @@ const getOffset = (el) => { } } return { top: y, left: x }; +}; +const isScrolledIntoView = (elem) => { + const rect = elem.getBoundingClientRect(); + const elemTop = rect.top; + const elemBottom = rect.bottom; + // Only completely visible elements return true: + const isVisible = elemTop >= 0 && elemBottom <= window.innerHeight; + // Partially visible elements return true: + // isVisible = elemTop < window.innerHeight && elemBottom >= 0; + return isVisible; }; /** @@ -19744,9 +19754,15 @@ class PlexMeetsHomeAssistant extends HTMLElement { if (this.data[this.config.libraryName]) { // eslint-disable-next-line consistent-return const searchValues = lodash.split(this.searchValue, ' '); + let lastRowTop = 0; + let columnsCount = 0; + let maxRenderCount = false; + const loadAdditionalRowsCount = 2; // todo: make this configurable // eslint-disable-next-line consistent-return lodash.forEach(this.data[this.config.libraryName], (movieData) => { - if (!this.maxCount || count < this.maxCount) { + if ((!this.maxCount || count < this.maxCount) && (!maxRenderCount || count < maxRenderCount)) { + const movieElem = this.getMovieElement(movieData); + let shouldRender = false; if (this.looseSearch) { let found = false; // eslint-disable-next-line consistent-return @@ -19757,14 +19773,26 @@ class PlexMeetsHomeAssistant extends HTMLElement { } }); if (found || lodash.isEmpty(searchValues[0])) { - this.content.appendChild(this.getMovieElement(movieData)); - count += 1; + shouldRender = true; } } else if (lodash.includes(lodash.toUpper(movieData.title), lodash.toUpper(this.searchValue))) { - this.content.appendChild(this.getMovieElement(movieData)); + shouldRender = true; + } + if (shouldRender) { + this.content.appendChild(movieElem); count += 1; } + if (lastRowTop !== movieElem.getBoundingClientRect().top) { + if (lastRowTop !== 0 && columnsCount === 0) { + columnsCount = count - 1; + } + lastRowTop = movieElem.getBoundingClientRect().top; + if (!isScrolledIntoView(movieElem) && !maxRenderCount) { + maxRenderCount = count - 1 + columnsCount * loadAdditionalRowsCount; + console.log(`Set max render count to ${maxRenderCount}`); + } + } } else { return true; diff --git a/src/modules/utils.ts b/src/modules/utils.ts index 8607c29..a1bc21a 100644 --- a/src/modules/utils.ts +++ b/src/modules/utils.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-env browser */ import _ from 'lodash'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const escapeHtml = (unsafe: any): string => { @@ -34,5 +35,17 @@ const getOffset = (el: Element): Record => { return { top: y, left: x }; }; +const isScrolledIntoView = (elem: HTMLElement): boolean => { + const rect = elem.getBoundingClientRect(); + const elemTop = rect.top; + const elemBottom = rect.bottom; + + // Only completely visible elements return true: + const isVisible = elemTop >= 0 && elemBottom <= window.innerHeight; + // Partially visible elements return true: + // isVisible = elemTop < window.innerHeight && elemBottom >= 0; + return isVisible; +}; + // eslint-disable-next-line import/prefer-default-export -export { escapeHtml, getOffset }; +export { escapeHtml, getOffset, isScrolledIntoView }; diff --git a/src/plex-meets-homeassistant.ts b/src/plex-meets-homeassistant.ts index ffe4aea..752f00b 100644 --- a/src/plex-meets-homeassistant.ts +++ b/src/plex-meets-homeassistant.ts @@ -5,7 +5,7 @@ import _ from 'lodash'; import { supported, CSS_STYLE } from './const'; import Plex from './modules/Plex'; import PlayController from './modules/PlayController'; -import { escapeHtml, getOffset } from './modules/utils'; +import { escapeHtml, getOffset, isScrolledIntoView } from './modules/utils'; import style from './modules/style'; class PlexMeetsHomeAssistant extends HTMLElement { @@ -246,8 +246,18 @@ class PlexMeetsHomeAssistant extends HTMLElement { // eslint-disable-next-line consistent-return const searchValues = _.split(this.searchValue, ' '); // eslint-disable-next-line consistent-return + let rowsRendered = 0; + let lastRowTop = 0; + let columnsCount = 0; + const keepRendering = true; + let maxRenderCount: any = false; + + const loadAdditionalRowsCount = 2; // todo: make this configurable + // eslint-disable-next-line consistent-return _.forEach(this.data[this.config.libraryName], (movieData: Record) => { - if (!this.maxCount || count < this.maxCount) { + if (keepRendering && (!this.maxCount || count < this.maxCount) && (!maxRenderCount || count < maxRenderCount)) { + const movieElem = this.getMovieElement(movieData); + let shouldRender = false; if (this.looseSearch) { let found = false; // eslint-disable-next-line consistent-return @@ -258,13 +268,26 @@ class PlexMeetsHomeAssistant extends HTMLElement { } }); if (found || _.isEmpty(searchValues[0])) { - this.content.appendChild(this.getMovieElement(movieData)); - count += 1; + shouldRender = true; } } else if (_.includes(_.toUpper(movieData.title), _.toUpper(this.searchValue))) { - this.content.appendChild(this.getMovieElement(movieData)); + shouldRender = true; + } + if (shouldRender) { + this.content.appendChild(movieElem); count += 1; } + if (lastRowTop !== movieElem.getBoundingClientRect().top) { + if (lastRowTop !== 0 && columnsCount === 0) { + columnsCount = count - 1; + } + lastRowTop = movieElem.getBoundingClientRect().top; + rowsRendered += 1; + if (!isScrolledIntoView(movieElem) && !maxRenderCount) { + maxRenderCount = count - 1 + columnsCount * loadAdditionalRowsCount; + console.log(`Set max render count to ${maxRenderCount}`); + } + } } else { return true; }