Flamov/steamchat-website

View on GitHub
resources/assets/js/modules/archive.js

Summary

Maintainability
D
1 day
Test Coverage
let $archives;
const episodeCache = {
    years: {},
    categories: {}
};

function createCache() {
    $archives.$sidebar.$years = $archives.$sidebar.getElementsByClassName('js-year');
    $archives.$sidebar.$categories = $archives.$sidebar.getElementsByClassName('js-category');

    const filterArray = function(key, attribute) {
        return Array.prototype.filter.call($archives.$episodes, function(episode) {
            return episode.getAttribute(attribute) === key;
        });
    };

    // Cache episodes by year
    for (let i = 0; i < $archives.$sidebar.$years.length; i++) {
        // Get the element
        let targetElement = $archives.$sidebar.$years[i];

        // Get the year value
        const targetYear = targetElement.value;

        // Check if the object property already exists
        if (episodeCache.years.hasOwnProperty(targetYear) === false) {
            episodeCache.years[targetYear] = filterArray(targetYear, 'data-year');
        }
    }

    // Cache episodes by category
    for (let i = 0; i < $archives.$sidebar.$categories.length; i++) {
        // Get the element
        let targetElement = $archives.$sidebar.$categories[i];

        // Get the category value
        const targetCategory = targetElement.value;

        // Check if the object property already exists
        if (targetCategory !== 'all' && episodeCache.categories.hasOwnProperty(targetCategory) === false) {
            episodeCache.categories[targetCategory] = filterArray(targetCategory, 'data-category');
        }
    }

}

function searchBehaviour() {
    let value = this.value;

    // Ignore non-alphanumeric and whitespace characters
    value = value.replace(/[^a-zA-Z0-9]/gi, ' ');

    // Then replace multiple spaces with a single space
    value = value.replace(/\s\s+/g, ' ');

    const regex = new RegExp(value, 'gi');

    for (let i = 0; i < $archives.$episodes.length; i++) {
        const targetElement = $archives.$episodes[i];
        let description = targetElement.getAttribute('data-description');
        if (description.search(regex) < 0) {
            targetElement.classList.add('filter-description');
        }
        else {
            targetElement.classList.remove('filter-description');
        }
    }

    if (value !== '') {
        $archives.$sidebar.$search.classList.add('active');
    }
    else {
        $archives.$sidebar.$search.classList.remove('active');
    }

    updateFilteringDisplay();
}

function yearsBehaviour() {
    const totalLength = $archives.$sidebar.$years.length;
    let yearsActive = 0;
    for (let i = 0; i < $archives.$sidebar.$years.length; i++) {
        if ($archives.$sidebar.$years[i].checked === true) {
            yearsActive++;
        }
    }
    yearsActive = totalLength - (totalLength - yearsActive);

    // If this is the last checkbox checked, prevent it from becoming unchecked
    if (this.checked === false && yearsActive < 1) {
        this.checked = true;
    }
    else {
        this.disabled = false;
        const selectedYear = episodeCache.years[this.value];

        // Loop through the year of episodes corresponding to the year checkbox value
        for (let i = 0; i < selectedYear.length; i++) {
            const targetEpisode = selectedYear[i];
            if (this.checked === true) {
                targetEpisode.classList.remove('filter-year');
            }
            else {
                targetEpisode.classList.add('filter-year');
            }
        }

        // Disable last checkbox if only one left, otherwise enable all checkboxes
        for (let i = 0; i < $archives.$sidebar.$years.length; i++) {
            if (yearsActive <= 1 && $archives.$sidebar.$years[i].checked === true) {
                $archives.$sidebar.$years[i].disabled = true;
                break;
            }
            else {
                $archives.$sidebar.$years[i].disabled = false;
            }
        }

    }

    updateFilteringDisplay();
}

function categoryBehaviour() {
    const selectedCategory = this.value;

    if (selectedCategory === 'all') {
        for (let i = 0; i < $archives.$episodes.length; i++) {
            $archives.$episodes[i].classList.remove('filter-category');
        }
    }
    else {
        for (let i = 0; i < $archives.$episodes.length; i++) {
            $archives.$episodes[i].classList.add('filter-category');
        }

        const targetCategory = episodeCache.categories[selectedCategory];
        for (let i = 0; i < targetCategory.length; i++) {
            targetCategory[i].classList.remove('filter-category');
        }
    }

    updateFilteringDisplay();
}

function resetBehaviour(event) {
    if (event !== null) {
        event.preventDefault();
    }

    // Reset the search field
    $archives.$sidebar.$search.value = '';
    $archives.$sidebar.$search.classList.remove('active');

    // Reset the year inputs
    for (let i = 0; i < $archives.$sidebar.$years.length; i++) {
        const targetCheckbox = $archives.$sidebar.$years[i];
        targetCheckbox.checked = true;
        targetCheckbox.disabled = false;
    }

    // Reset the category inputs
    for (let i = 0; i < $archives.$sidebar.$categories.length; i++) {
        const targetCategory = $archives.$sidebar.$categories[i];
        if (targetCategory.value === 'all') {
            targetCategory.checked = true;
            break;
        }
    }

    // Reset the episode elements
    for (let i = 0; i < $archives.$episodes.length; i++) {
        $archives.$episodes[i].classList.remove('filter-description', 'filter-year', 'filter-category');
    }

    // Update filering display
    updateFilteringDisplay();
}

function updateFilteringDisplay() {
    const total = $archives.$episodes.length;
    let hiding = 0;

    const filterClasses = [
        'filter-description',
        'filter-year',
        'filter-category'
    ];

    // Function to check if any of the filter classes are present in the element class list
    const checkClass = function(element) {
        for (let i = 0; i < filterClasses.length; i++) {
            if (element.classList.contains(filterClasses[i]) === true) {
                return true;
            }
        }
        return false;
    };

    // Loop through each episode elements and increase the hiding count if it contains any filter classes
    for (let i = 0; i < $archives.$episodes.length; i++) {
        if (checkClass($archives.$episodes[i]) === true) {
            hiding++;
        }
    }

    const showing = total - hiding;
    if (showing < total) {
        $archives.$counter.innerHTML = 'Showing ' + showing + ' of ' + total + ' episodes:';
        $archives.classList.add('filtering');
        $archives.$sidebar.classList.add('active');
    }
    else {
        $archives.classList.remove('filtering');
    }

    if (showing === 0) {
        $archives.classList.add('empty');
    }
    else {
        $archives.classList.remove('empty');
    }
}

export function init(element) {
    // Cache element selectors
    $archives = element;
        $archives.$sidebar = $archives.getElementsByClassName('js-sidebar')[0];
            $archives.$sidebar.$search = $archives.$sidebar.getElementsByClassName('js-search')[0];
            $archives.$sidebar.$years = $archives.$sidebar.getElementsByClassName('js-year');
            $archives.$sidebar.$categories = $archives.$sidebar.getElementsByClassName('js-category');
        $archives.$episodes = $archives.getElementsByClassName('js-episode');
        $archives.$counter = $archives.getElementsByClassName('js-count')[0];

    /*** Bind sidebar scrolling ***/
    window.addEventListener('scroll', function() {
        const padding = 40;
        if (window.scrollY > ($archives.offsetTop - padding)) {
            $archives.$sidebar.classList.add('sticky');
        }
        else {
            $archives.$sidebar.classList.remove('sticky');
        }
    });

    /*** Caching episodes and inputs by years and categories ***/
    createCache();

    /*** Bind Show Button ***/
    const show = $archives.getElementsByClassName('js-show');
    if (show.length > 0) {
        show[0].addEventListener('click', function(event) {
            event.preventDefault();
            if ($archives.$sidebar.classList.contains('active') === true) {
                resetBehaviour(null);
            }
            $archives.$sidebar.classList.toggle('active');
        });
    }

    /*** Bind Search ***/
    $archives.$sidebar.$search.addEventListener('input', searchBehaviour);

    /*** Bind Year Inputs ***/
    for (let i = 0; i < $archives.$sidebar.$years.length; i++) {
        $archives.$sidebar.$years[i].addEventListener('change', yearsBehaviour);
    }

    /*** Bind Category Inputs ***/
    for (let i = 0; i < $archives.$sidebar.$categories.length; i++) {
        $archives.$sidebar.$categories[i].addEventListener('change', categoryBehaviour);
    }

    /*** Bind Reset Button ***/
    const reset = $archives.getElementsByClassName('js-reset');
    for (let i = 0; i < reset.length; i++) {
        reset[i].addEventListener('click', resetBehaviour);
    }
}