Source: plugins/column-resizer.js

import BasePlugin from "../core/base-plugin.js";
import elementOffset from "../utils/elementOffset.js";
import {
    addClass,
    dispatch,
    findAll,
    getAttribute,
    hasClass,
    off,
    on,
    removeAttribute,
    removeClass,
    setAttribute,
} from "../utils/shortcuts.js";

/**
 * Allows to resize columns
 */
class ColumnResizer extends BasePlugin {
    constructor(grid) {
        super(grid);
        this.isResizing = false;
    }

    /**
     * @param {String} resizeLabel
     */
    renderResizer(resizeLabel) {
        const grid = this.grid;
        const table = grid.table;
        const cols = findAll(grid, "thead tr.dg-head-columns th");

        for (const col of cols) {
            if (hasClass(col, "dg-not-resizable")) {
                continue;
            }
            // Create a resizer element
            const resizer = document.createElement("div");
            addClass(resizer, "dg-resizer");
            resizer.ariaLabel = resizeLabel;

            // Add a resizer element to the column
            col.appendChild(resizer);

            // Handle resizing
            let startX = 0;
            let startW = 0;
            let remainingSpace = 0;
            let max = 0;

            const mouseMoveHandler = (e) => {
                if (e.clientX > max) {
                    return;
                }
                const newWidth = startW + (e.clientX - startX);
                if (col.dataset.minWidth && newWidth > Number.parseInt(col.dataset.minWidth)) {
                    setAttribute(col, "width", newWidth);
                }
            };

            // When user releases the mouse, remove the existing event listeners
            const mouseUpHandler = () => {
                grid.log("resized column");

                // Prevent accidental sorting if mouse is not over resize handler
                setTimeout(() => {
                    this.isResizing = false;
                }, 0);

                removeClass(resizer, "dg-resizer-active");
                if (grid.options.reorder) {
                    col.draggable = true;
                }
                col.style.overflow = "hidden";

                // Remove handlers
                off(document, "mousemove", mouseMoveHandler);
                off(document, "mouseup", mouseUpHandler);

                dispatch(grid, "columnResized", {
                    col: getAttribute(col, "field"),
                    width: getAttribute(col, "width"),
                });
            };

            // Otherwise it could sort the col
            on(resizer, "click", (e) => {
                e.stopPropagation();
            });

            on(resizer, "mousedown", (e) => {
                e.stopPropagation();

                this.isResizing = true;

                const target = e.target;
                const currentCols = findAll(grid, "dg-head-columns th");
                const visibleCols = currentCols.filter((col) => {
                    return !col.hasAttribute("hidden");
                });
                const columnIndex = visibleCols.findIndex((column) => column === target.parentNode);
                grid.log("resize column");

                addClass(resizer, "dg-resizer-active");

                // Make sure we don't drag it
                removeAttribute(col, "draggable");

                // Allow overflow when resizing
                col.style.overflow = "visible";

                // Show full column height (-1 to avoid scrollbar)
                resizer.style.height = `${table.offsetHeight - 1}px`;

                // Register initial data
                startX = e.clientX;
                startW = col.offsetWidth;

                remainingSpace = (visibleCols.length - columnIndex) * 30;
                max = elementOffset(target).left + grid.offsetWidth - remainingSpace;

                // Remove width from next columns to allow auto layout
                setAttribute(col, "width", startW);
                for (let j = 0; j < visibleCols.length; j++) {
                    if (j > columnIndex) {
                        removeAttribute(cols[j], "width");
                    }
                }

                // Attach handlers
                on(document, "mousemove", mouseMoveHandler);
                on(document, "mouseup", mouseUpHandler);
            });
        }
    }
}

export default ColumnResizer;