Skip to content

Source: lib/dom/sortElements.js

/**
 * Sorts the direct child elements of a container by their `data-sort` attribute.
 * Elements with:
 * - `data-sort < 0` → Excluded from sorting, moved last, and get `tabindex="-1"`.
 * - `data-sort ≥ 0` → Sorted in ascending order.
 * - no `data-sort`  → Appended before or after the sorted items depending on `sortOrder`.
 * @exports module:lib/dom/sortElements
 * @author  Frank Kudermann - alphanull
 * @version 1.0.0
 * @license MIT
 */
export default sortElements;

/**
 * Sorts the direct child elements of a container by their `data-sort` attribute.
 * @memberof module:lib/dom/sortElements
 * @param {HTMLElement}      container    The container whose children should be sorted.
 * @param {'sorted-last'|''} [sortOrder]  Determines whether sorted items come after (`'sorted-last'`) or before the unsorted ones.
 */
function sortElements(container, sortOrder = '') {

    const children = Array.from(container.children),
          staticNodes = [],
          sortedNodes = [],
          unsortedNodes = [];

    children.forEach(node => {

        const attr = node.getAttribute('data-sort');
        node.removeAttribute('data-sort');

        if (attr === null) {
            // No data-sort defined
            unsortedNodes.push(node);
            return;
        }

        const value = parseInt(attr, 10);

        if (isNaN(value)) {
            unsortedNodes.push(node);
            return;
        }

        if (value < 0) {
            node.setAttribute('tabindex', '-1');
            staticNodes.push(node);
            return;
        }

        sortedNodes.push({ node, value });

    });

    // Sort numeric entries ascending
    sortedNodes.sort((a, b) => a.value - b.value);

    const sortedList = sortedNodes.map(({ node }) => node),
          finalOrder = sortOrder === 'sorted-last'
              ? [...unsortedNodes, ...sortedList, ...staticNodes]
              : [...sortedList, ...unsortedNodes, ...staticNodes];

    finalOrder.forEach(node => container.appendChild(node)); // Re-append in new order

}