Source: views/renderAdvents.js

/**
 * @module renderAdvents
 */
import { advents, tags } from './advents.js';

/**
 * @constant
 * @type {Object[][]}
 * @name adventDomGroups
 * @description Array of Advent Group and Advent DOMs
 */
const adventDomGroups = advents
    // Map Each Advent in a Group to an Advent DOM
    .map(group =>
        group.map(advent => ({
            advent,
            adventDiv: renderAdvent(advent)
        }))
    )
    // Map Each Group to an Advent Group DOM
    .map(group => ({
        group,
        groupDom: renderAdventGroup(group)
    }));

/**
 * @function
 * @name renderAdvent
 * @description Render Advent DOM Object from Advent Object
 * @param {Object} advent Advent Object
 * @returns {HTMLElement} Advent DOM Object
 */
function renderAdvent(advent) {

    // Advent div
    const adventDiv = document.createElement('div');
    adventDiv.classList.add('advent');

    // Title p
    const titleP = document.createElement('p');
    titleP.classList.add('title');
    titleP.classList.add('mono-text');
    titleP.innerText = advent.title;
    adventDiv.appendChild(titleP);

    // Date p
    const dateP = document.createElement('p');
    dateP.classList.add('date');
    dateP.classList.add('mono-text');
    dateP.innerText = (
        `${advent.start.month}/${advent.start.day}/${advent.start.year}` +
        ((advent.end === null)
            ? ''
            : `-${advent.end.month}/${advent.end.day}/${advent.end.year}`)
    );
    adventDiv.appendChild(dateP);

    // Tags p
    const tagsP = document.createElement('p');
    tagsP.classList.add('tags');
    tagsP.classList.add('mono-text');
    tagsP.innerText = `Tags:${advent.tags.join(',')}`;
    adventDiv.appendChild(tagsP);

    // Content p
    const contentP = document.createElement('p');
    contentP.classList.add('content');
    contentP.classList.add('read-text');
    contentP.innerText = advent.content;
    adventDiv.appendChild(contentP);

    return adventDiv;
}

/**
 * @function
 * @name renderAdventGroup
 * @description Render Advent Group DOM Object from Advent Group
 * @param {Object[]} group Advent Group
 * @returns {HTMLElement} Advent Group DOM Object
 */
function renderAdventGroup(group) {

    // Group div
    const groupDiv = document.createElement('div');
    groupDiv.classList.add('group');

    // Date Toggle p
    const dateToggleP = document.createElement('p');
    dateToggleP.classList.add('group-date');
    dateToggleP.classList.add('mono-text');
    dateToggleP.addEventListener('click', toggleVisibility());
    const { advent: { start: { month, day, year } } } = group[0];
    const date = `${month}/${day}/${year}`;
    dateToggleP.innerText = `${date} [▼]`;
    groupDiv.appendChild(dateToggleP);

    // Advents div
    const adventsDiv = document.createElement('div');
    adventsDiv.classList.add('advents');
    adventsDiv.classList.add('hidden');
    groupDiv.appendChild(adventsDiv);

    return groupDiv;
}

/**
 * @function
 * @name renderTagToggles
 * @description Render Tag Toggles from Tags
 * @param {HTMLElement} target1 Target to render Tag Toggles
 * @param {HTMLElement} target2 Target to render Timeline
 */
export function renderTagToggles(target1, target2) {

    // Toggle Title p
    const toggleTitle = document.createElement('p');
    toggleTitle.classList.add('toggle-container-title');
    toggleTitle.classList.add('mono-text');
    toggleTitle.innerText = 'Tags [▼]';
    toggleTitle.addEventListener('click', toggleVisibility());
    target1.appendChild(toggleTitle);

    // Toggle Container div
    const toggleContainer = document.createElement('div');
    toggleContainer.classList.add('toggles-container');
    toggleContainer.classList.add('hidden');
    target1.appendChild(toggleContainer);

    // Add Tag Toggle per Tag Key
    for (const key of tags.keys()) {

        // Tag Toggle div
        const tagToggleDiv = document.createElement('div');
        tagToggleDiv.classList.add('toggle-container');

        // Tag Toggle Checkbox input
        const tagToggleCheck = document.createElement('input');
        tagToggleCheck.setAttribute('type', 'checkbox');
        tagToggleCheck.setAttribute('checked', true);
        tagToggleCheck.classList.add('tag-toggle');
        tagToggleCheck.addEventListener('click', () => {
            tags.set(key, !tags.get(key));
            renderTimeline(target2);
        });
        tagToggleDiv.appendChild(tagToggleCheck);

        // Tag Toggle Label label
        const tagToggleLabel = document.createElement('label');
        tagToggleLabel.classList.add('tag-toggle-label');
        tagToggleLabel.classList.add('mono-text');
        tagToggleLabel.innerText = key;
        tagToggleDiv.appendChild(tagToggleLabel);

        toggleContainer.appendChild(tagToggleDiv);
    }

}

/**
 * @function
 * @name toggleVisibility
 * @description Creates Function to toggle Visibility of Element given a Find Function
 * @param {Function} findFn Function to find Element to Toggle from Target
 * @returns {Function} Function to toggle Visibility of Element
 */
function toggleVisibility(findFn = target => target.nextElementSibling) {
    // Function to toggle Visibility
    return function ({ target }) {
        // Element to Toggle
        const container = findFn(target);
        const end = target.innerText.length - 3;
        // Hide Element
        if (target.innerText.endsWith('[▼]')) {
            container.classList.remove('hidden');
            target.innerText = `${target.innerText.slice(0, end)}[▲]`;
        }
        // Show Element
        else {
            container.classList.add('hidden');
            target.innerText = `${target.innerText.slice(0, end)}[▼]`;
        }
    };
}

/**
 * @function
 * @name renderTimeline
 * @description Render Timeline from Advent DOM Groups
 * @param {HTMLElement} target Target to render Timeline
 */
export function renderTimeline(target) {
    // Clear Timeline
    removeChildren(target);
    // For every Advent DOM Group
    for (const { group, groupDom } of adventDomGroups) {
        const [_, advents] = groupDom.children;
        // Remove all Advents from Advent Group DOM
        removeChildren(advents);
        // Append Advent if some Tag is toggled
        for (const { advent, adventDiv } of group) {
            if (advent.tags.some(tag => tags.get(tag))) {
                advents.appendChild(adventDiv);
            }
        }
        // Append Advent Group DOM if not empty
        if (advents.firstChild) {
            target.appendChild(groupDom);
        }
    }
}

/**
 * @function
 * @name removeChildren
 * @description Removes all children elements from Target Element
 * @param {HTMLElement} element Target Element
 */
function removeChildren(element) {
    while (element.firstChild) {
        element.removeChild(element.firstChild);
    }
}