domUI/inventoryUI.js

const INVENTORY_PROPS = {
    className : "club-crawler-inventory",
    style: {
    }
}

const INVENTORY_CONTAINER_PROPS = {
    id : "club-crawler-inventory-slots-container",
    style: {
        display: "flex",
        flexWrap: "wrap",
        aligItems: "stretch",
        gap: "10px",
        alignContent: "end",
        boxSizing:"border-box"
    }
}

const TITLE_PROPS = {
    id: "club-crawler-inventory-title",
    style: {
        width: "100%"
    },
    innerHTML: "Inventory"
}

const SLOT_PROPS = {
    className: "club-crawler-inventory-slot",
    style: {
        height: "55px",
        width: "55px",
        position: "relative"
    }
}

const SLOT_IMG_PROPS = {
    className: "club-crawler-inventory-slot-image",
    style: {
        height: "100%",
        width: "100%",
        top: "0px",
        left: "0px",
        position: "absolute"
    }
}

const SLOT_QTY_PROPS = {
    className: "club-crawler-inventory-slot-qty",
    style: {
        height: "100%",
        width: "100%",
        position: "absolute",
        top: "2px",
        left: "2px"
    }
}

/**
 * @classdesc The inventory user interface.
 * @memberof ClubCrawler.DOMUserInterface
 */
class InventoryUI {
    /**
     * @param {HTMLElement} element - The container element.
     */
    constructor(element) {
        /** @member {HTMLElement} - The containing html element. */
        this.element = element;
        Object.assign(this.element, INVENTORY_PROPS);      
        Object.assign(this.element.style, INVENTORY_PROPS.style);
        /** @member {HTMLElement} - Contains the word "inventory". */
        this.titleElement = document.createElement('div');
        Object.assign(this.titleElement, TITLE_PROPS);
        Object.assign(this.titleElement.style, TITLE_PROPS.style);
        /** @member {HTMLElement} - Contains the inventory slot displays. */
        this.slotsContainer = document.createElement('div');
        Object.assign(this.slotsContainer, INVENTORY_CONTAINER_PROPS);
        Object.assign(this.slotsContainer.style, INVENTORY_CONTAINER_PROPS.style);
        this.element.appendChild(this.titleElement);
        this.element.appendChild(this.slotsContainer);
        /** @member {Array} - The inventory slots. */
        this.slots = [];
        /** @member {ClubCrawler.Objects.Inventory.Inventory} - The inventory to interface with, loaded on runtime. */
        this.inventory = null;
        /** @member {ClubCrawler.Objects.DOMUserInterface.DOMUIManager} - The UI manager, loaded on runtime. */
        this.uiManager = null;
        /** @member {ClubCrawler.Objects.Inventory.InventoryItemSlot} - An inventory item slot which is being dragged. */
        this.draggingSlot = null;
        /** @member {ClubCrawler.Objects.Inventory.InventoryItemSlot} - An inventory item slot which is being dragged over. */
        this.draggingOverSlot = null;
    }

    /**
     * Loads the UI Manager.
     * 
     * @param {ClubCrawler.DOMUserInterface.DOMUIManager} uiManager - The UI Manager.
     */
    loadManager(uiManager) {
        this.uiManager = uiManager;
        for(let slot of this.slots) {
            slot.loadManager(this.uiManager);
        }
    }

    /**
     * Loads an inventory.
     * 
     * @param {ClubCrawler.Objects.Inventory.Inventory} inventory - The inventory to be displayed.
     */
    loadInventory(inventory) {
        this.clearInventory();
        this.inventory = inventory;
        // probably gonna make dup. inventories on scene reload
        for(let itemSlot of inventory.itemSlots) {
            let itemUI = new ItemSlotUI(this.slotsContainer, itemSlot);
            if(this.uiManager) {
                itemUI.loadManager(this.uiManager);
            }
            this.slots.push(itemUI);
        }
        this.setDragListeners();
    }

    /**
     * Sets event listeners and logic for the drag-to-rearrange functionality of the inventory UI.
     */
    setDragListeners() {
        var inventoryUI = this;
        for(let itemUI of this.slots) {
            itemUI.element.addEventListener('dragstart', (event)=> {
                if(!itemUI.slot.empty) {
                    inventoryUI.draggingSlot = itemUI.slot;
                }
            })
            itemUI.element.addEventListener('dragenter', (event)=> {
                inventoryUI.draggingOverSlot = itemUI.slot;
            })
            itemUI.element.addEventListener('dragend', (event)=> {
                if(inventoryUI.draggingOverSlot) {
                    inventoryUI.inventory.swapSlots(inventoryUI.draggingSlot, inventoryUI.draggingOverSlot);
                    let inventory = inventoryUI.inventory;
                    inventoryUI.clearInventory();
                    inventoryUI.loadInventory(inventory);
                }
            })
        }
    }

    /**
     * Calls updateDisplay on each UI slot to refresh it from inventory.
     */
    refreshInventory() {
        for(let slot of this.slots) {
            slot.updateDisplay();
        }
    }
    /**
     * Clears inventory and DOM elements.
     */
    clearInventory() {
        this.slots = []
        this.inventory = null;
        this.slotsContainer.innerHTML = "";
    }
}

/**
 * @classdesc UI component representing an inventory slot.
 * @memberof ClubCrawler.DOMUserInterface
 */
class ItemSlotUI {
    /**
     * Represents an Inventory Item Slot on the UI.
     * 
     * @param {HTMLElement} parentElement - The container element one level above this.
     * @param {ClubCrawler.Objects.Inventory.InventoryItemSlot} itemSlot - The inventory item slot to be represented.
     */
    constructor(parentElement, itemSlot) {
        /** @property {HTMLElement} - The parent container. */
        this.parentElement = parentElement;
        /** @property {ClubCrawler.Objects.Inventory.InventoryItemSlot} - the linked inventory item slot represented by this component.*/
        this.slot = itemSlot;
        /** @property {HTMLElement} - The container for the inventory image and quantity. */
        this.element = document.createElement('div');
        Object.assign(this.element, SLOT_PROPS);
        Object.assign(this.element.style, SLOT_PROPS.style);
        /** @property {HTMLImageElement} - An image of the item as it appears in inventory. */
        this.image = document.createElement('img');
        Object.assign(this.image, SLOT_IMG_PROPS);
        Object.assign(this.image.style, SLOT_IMG_PROPS.style);
        /** @property {HTMLElement} - Displays quantity in inventory of stackable items. */
        this.qty = document.createElement('div');
        Object.assign(this.qty, SLOT_QTY_PROPS);
        Object.assign(this.qty.style, SLOT_QTY_PROPS.style);
        this.element.appendChild(this.qty);
        this.element.appendChild(this.image);
        this.parentElement.appendChild(this.element);
        /** @property {ClubCrawler.DOMUserInterface.DOMUIManager} - The manager. */
        this.uiManager = null;
        this.updateDisplay();        
    }
    /**
     * Updates display from the linked inventory item slot.
     */
    updateDisplay() {
        if(!this.slot.empty) {
            this.image.src = this.slot.parentInventory.scene.textures.list[this.slot.instanceConfig.inventorySprite].frames.__BASE.source.source.src;
            this.image.title = this.slot.instanceConfig.name;
            if(this.slot.itemType != "stackable") {
                this.qty.innerHTML = "";
            }
            else {
                this.qty.innerHTML = this.slot.quantity;
            }
        }
        else {
            this.image.src = "";
            this.image.title = "";
            this.qty.innerHTML = "";
        }
    }
    /**
     * Loads the UI Manager adds a click listener which calls [uiManager.slotClick]{@link ClubCrawler.DOMUserInterface.DOMUIManager#slotClick} when this slotUI is clicked, passing the linked [itemSlot]{@link ClubCrawler.Objects.Inventory.InventoryItemSlot} as a parameter.
     * @param {ClubCrawler.DOMUserInterface.DOMUIManager} uiManager - The manager
     */
    loadManager(uiManager) {
        this.uiManager = uiManager;
        var slot = this.slot;
        this.element.addEventListener('click', (ev)=> {
            uiManager.slotClick(slot)
        })
    }
}

module.exports = InventoryUI;