Source: media/data/GridDataFiltered.js

import { GridData } from "./GridData.js";
import { ClientFilter } from "../filter/client/ClientFilter.js";
export { GridDataFiltered }

/**
 * Class representing filtered grid data.
 * Note: Filter is based on client data level.
 */
class GridDataFiltered extends GridData {
    /**
     * Create the filtered grid data object.
     * @param {Object} galleryConfigDict - Gallery configuration dictionary.
     */
    constructor(galleryConfigDict) {
        super(galleryConfigDict);
        this.galleryItems = [];
        this.gallerySourceIndices = [];

        const settingsClientFilter = {
            'duplicateFilter': galleryConfigDict?.filters?.["duplicateFilter"],
            'demoHeightFilter': galleryConfigDict?.filters?.["demoHeightFilter"]
        };
        this.galleryClientFilter = new ClientFilter(settingsClientFilter);
    }

    /**
     * Get the amount of items without filtered items. 
     */
    get galleryItemAmount() {
        return this.gallerySourceIndices.length
    }

    _getDataItemIndex(index) {
        const dataItemIndex = (index + super.dataItemAmount) % super.dataItemAmount;
        if (isNaN(dataItemIndex))
            return null
        if (dataItemIndex < 0)
            return this._getGalleryItemIndex(dataItemIndex)
        return dataItemIndex
    }

    _getGalleryItemIndex(index) {
        const galleryItemIndex = (index + this.galleryItemAmount) % this.galleryItemAmount;
        if (isNaN(galleryItemIndex))
            return null
        if (galleryItemIndex < 0)
            return this._getGalleryItemIndex(galleryItemIndex)
        return galleryItemIndex
    }

    _getBufferInfo(index, bufferSize) {
        const bufferStart = bufferSize[0];
        const bufferEnd = bufferSize[1];
        const bufferSteps = Array.from({ length: bufferEnd - bufferStart + 1 }, (_, idx) => idx + bufferStart); //[-2, -1, 0, 1, 2]]

        const bufferIndices = bufferSteps.map(idx => this._getGalleryItemIndex(index + idx));
        const isBufferItemLoadedList = bufferIndices.map(idx => this.galleryItems[idx] != null);
        return [bufferIndices, isBufferItemLoadedList]
    }

    _bufferHelper(index, bufferSize) {
        const [bufferIndices, isBufferItemLoadedList] = this._getBufferInfo(index, bufferSize);

        let count = 0;
        let isRun, startIndex;

        for (let idx = 0; idx < isBufferItemLoadedList.length; idx++) {
            const isBufferItemLoaded = isBufferItemLoadedList[idx];
            if (!isBufferItemLoaded) {
                if (!isRun)
                    startIndex = bufferIndices[idx];
                count += 1;
                isRun = true;
            }
            else if (isRun)
                break
        }
        return [startIndex, count]
    }

    /**
     * Even if items are filtered, load items until the count is reached.
     * @param {Number} startIndex - Index where loading should start.
     * @param {Number} count - Number of items that should be loaded regardless of filtering.
     * @param {Boolean} reversed - Indicate if items are loaded backwards.
     * @param {Object} query - Custom query parameters for the request.
     * @param {Boolean} queueing - If true, load multiple requests synchronously via queue.
     * @returns Promise with updated start index.
     */
    loadItems(startIndex, count, reversed, query = {}, queueing = true) {

        let [startIndexNew, countNew] = this._bufferHelper(startIndex, [0, count - 1]);

        if (countNew != 0) {
            const startIndexNewSource = this.gallerySourceIndices.length == 0 ? startIndex : this.gallerySourceIndices[startIndexNew].at(-1);

            const lengthGalleryItemsBeforeLoading = this.galleryItems.length;
            return super.loadItems(startIndexNewSource, countNew, query, queueing).then(() => {
                [this.galleryItems, this.gallerySourceIndices] = this.galleryClientFilter.filterData(this.dataItemsHarmonized);

                if (reversed) {
                    const lengthGalleryItemsAfterLoading = this.galleryItems.length;
                    const numberFilteredItems = lengthGalleryItemsBeforeLoading - lengthGalleryItemsAfterLoading;
                    return this.loadItems(startIndex - numberFilteredItems, count, reversed, query, queueing)
                }
                return this.loadItems(startIndex, count, reversed, query, queueing)
            })
        }
        else {
            return Promise.resolve(startIndex)
        }
    }
}