class HtmlEditor extends EicComponent {
    constructor(el, context, options = {}) {
        super();
        this.el = el
        Object.assign(this, app.helpers.activeAttributes)
        Object.assign(this, app.helpers.basicDialogs) 
        
        this.components = [];
        this.context = context;
        this.externalHandlers = options.externalHandlers || {};
        this.images = options.images || [];
        this.tokens = options.tokens || [];
        this.tplStatus = options.templateStatus || [];
        
        this.buttonMap = this.buttonMap || {
            subject: ['heUndo','heToken'],
            header: ['heUndo', 'heLink', 'heTextAlignment', 'heToogleStyle', 'heChangeFontSize', 'heColorText', 'heImage', 'heToken'],
            main: ['heUndo', 'heTable', 'heAddTable', 'heLink', 'heList', 'heTextAlignment','heToogleStyle', 'heChangeFontSize', 'heColorText', 'heImage', 'heToken'],
            footer: ['heUndo', 'heLink', 'heTextAlignment', 'heToogleStyle', 'heChangeFontSize', 'heColorText', 'heImage', 'heToken'],
            altText: ['heUndo', 'heToken']
        };
        
        this.initialize();
        
        this.undoStack = [];
        this.redoStack = [];
        this.isUndoRedo = false;
        this.boldTextButton = null;
        this.lastModifiedSpan = null;
        this.linkUrlInput = null;
        this.spaceBefore = document.createTextNode('\u00A0');
        this.spaceAfter = document.createTextNode('\u00A0');
        
        if (HtmlEditor.instance) {
            return HtmlEditor.instance;
        }
        HtmlEditor.instance = this;
        this.injectStyles();
    }
    
    initialize() {
        
        const loadingMessage = this.el.querySelector('.tpl-loadingTools');
        const toolButtonsContainer = this.el.querySelector('.tpl-toolButtons');
        
        // Afficher "Loading..." et cacher le menu
        loadingMessage.style.display = 'block';
        toolButtonsContainer.style.display = 'none';
        
        this.buildToolButtons('subject');
        
        setTimeout(() => {
            this.setCursorToField('subject');
        }, 0);
        
        // Attendre le chargement des boutons puis afficher le menu et masquer "Loading..."
        setTimeout(() => {
            loadingMessage.style.display = 'none';
            toolButtonsContainer.style.display = 'block';
        }, 500); // Ajuste le délai si nécessaire
        
        this.components = Array.from(toolButtonsContainer.querySelectorAll('.tool-button')).map(button => ({
            el: button
        }));
        
        this.initEditorEvents();
        
        //*sanitize copy/paste
        ['.template-field.subject','.template-field.header', '.template-field.main', '.template-field.footer', '.template-field.altText'].forEach(selector => {
            const editor = this.el.querySelector(selector);
            editor.contentEditable = 'true';
            editor.addEventListener('paste', (event) => this.handlePaste(event));
            editor.addEventListener('input', (event) => this.saveState(event));
        });
    }
    
    buildToolButtons(fieldType) {
        
        const availableButtons = this.buttonMap[fieldType] || []
        const toolButtonsContainer = this.el.querySelector('.tpl-toolButtons')
        
        this.setCursorToField(fieldType);
        
        toolButtonsContainer.innerHTML = ''; // Init buttons
        
        //Manage tools buttons if Status != Submitted
        const isSubmitted = this.tplStatus === 'submitted' ? 'disabled' : '';
        
        const buttonTemplates = {
            // Add buttons by field permissions
            heUndo: `
                    <button eicbutton xsmall type="button" class="tool-button icon-back he-undo" data-tool="heUndo" data-trigger="undo"  ${isSubmitted}></button>
                `,heTable: `
                    <button eicbutton xsmall type="button" class="tool-button medium icon-table he-addTable" data-tool="heTable" title="Add table" data-trigger="showTableInput"  ${isSubmitted}></button>
                    <div id="he-tableContainer" class="he-tableContainer" style="display:none;">
                    <label xsmall for="he-tableRows">Number of Rows:</label>
                    <input eicinput xsmall type="number" id="he-tableRows" class="he-tableRows" min="1" placeholder="Enter rows">
                    <label xsmall for="he-tableCols">Number of Columns:</label>
                    <input eicinput xxsmall type="number" id="he-tableCols" class="he-tableCols" min="1" placeholder="Enter columns">
                    <div class="cols-2">
                        <div>
                            <label xsmall for="he-addTableBorders">Add Borders:</label>
                            <input eiccheckbox type="checkbox" id="he-addTableBorders" class="he-addTableBorders">
                        </div>
                        <div>
                            <label xsmall for="he-addTableCenter">Center in page:</label>
                            <input eiccheckbox type="checkbox" id="he-addTableCenter" class="he-addTableCenter">
                        </div>
                    </div>
                    <button eicbutton xsmall class="info tool-button he-confirmAddTable" data-trigger="createTable">Add Table</button>
                </div>
                `,
            heLink: `
                    <button eicbutton xsmall type="button" class="tool-button medium icon-link he-addLink" data-tool="heLink" title="Add link" data-trigger="showLinkInput" data-value="showLinkInput"  ${isSubmitted}></button>
                    <div id="he-linkContainer" class="he-linkContainer" style="display:none;">
                        <input eicinput xsmall type="text" id="he-linkText" name="he-linkText" class="he-linkText" placeholder="Enter Link Text" style="display:none;">
                        <input eicinput xsmall type="text" id="he-linkUrl" name="he-linkUrl" class="he-linkUrl" placeholder="Enter URL or em@il">
                        <button eicbutton xsmall class="info tool-button he-confirmAddLink" data-trigger="createLink">Add Link</button>
                    </div>
                `,
            heList: `
                    <button eicbutton xsmall type="button" class="tool-button medium icon-list-ul he-addList" data-tool="heList" title="Add list" data-trigger="showListSelector"  ${isSubmitted}></button>
                    <div id="he-addListContainer" class="he-addListContainer" style="display:none;">
                        <textarea eictextarea class="he-listItems" placeholder="Enter list items, one per line"></textarea>
                        <label xsmall>Choose list type :</label>
                        <label xsmall>
                            <input type="radio" class="he-listTypeBullet" name="listType" checked>
                            Bullet
                        </label>
                        <label xsmall>
                            <input type="radio" class="he-listTypeDash" name="listType">
                            Dash
                        </label>
                        <label xsmall>
                            <input type="radio" class="he-listTypeNumbered" name="listType">
                            Numbered
                        </label>
                        <button eicbutton xsmall class="info tool-button he-confirmAddListButton" data-trigger="confirmList">Add List</button>
                    </div>
                `,
            heTextAlignment: `
                    <button type="button" eicbutton xsmall class="tool-button icon-align-center he-alignCenter" data-tool="heTextAlignment" data-trigger="applyTextAlignment" data-value="center"  ${isSubmitted}></button>  
                    <button type="button" eicbutton xsmall class="tool-button icon-align-left he-alignLeft" data-tool="heTextAlignment" data-trigger="applyTextAlignment" data-value="left"  ${isSubmitted}></button>
                    <button type="button" eicbutton xsmall class="tool-button icon-align-right he-alignRight" data-tool="heTextAlignment" data-trigger="applyTextAlignment"  data-value="right"  ${isSubmitted}></button>
                `,
            heToogleStyle: `
                    <button type="button" eicbutton xsmall class="tool-button icon-format-underline he-underlineText" data-tool="heToogleStyle" data-trigger="toggleStyle" data-value="underline"  ${isSubmitted}></button>
                    <button type="button" eicbutton xsmall class="tool-button icon-format-bold he-boldText" data-tool="heToogleStyle" data-trigger="toggleStyle" data-value="bold"  ${isSubmitted}></button> 
                    <button type="button" eicbutton xsmall class="tool-button icon-format-italic he-italicText" data-tool="heToogleStyle" data-trigger="toggleStyle" data-value="italic"  ${isSubmitted}></button>
                `,
            heChangeFontSize:`
                    <button type="button" eicbutton xsmall class="tool-button icon-font-size-up he-increaseFontSize" data-tool="heChangeFontSize" data-trigger="changeFontSize" data-value="1"  ${isSubmitted}></button>
                    <button type="button" eicbutton xsmall class="tool-button icon-font-size-down he-decreaseFontSize" data-tool="heChangeFontSize" data-trigger="changeFontSize" data-value="-1"  ${isSubmitted}></button>
                `,
            heColorText: `
                    <button type="button" eicbutton xsmall class="tool-button icon-format-color he-colorText" data-tool="heColorText" data-trigger="showColorPalette"  ${isSubmitted}></button>
                    <div id="he-colorPalette" class="he-colorPalette" style="display:none;">
                        <div class="he-colorOption black" style="background-color: var(--eicui-base-color-black);" data-trigger="applyColorToText" data-value="var(--eicui-base-color-black)"></div>
                        <div class="he-colorOption primary" style="background-color:var(--eicui-base-color-primary-100);"  data-trigger="applyColorToText" data-value="var(--eicui-base-color-primary-100)"></div>
                        <div class="he-colorOption info" style="background-color: var(--eicui-base-color-info-100);" data-trigger="applyColorToText" data-value="var(--eicui-base-color-info-100)"></div>
                        <div class="he-colorOption success" style="background-color: var(--eicui-base-color-success-100);" data-trigger="applyColorToText" data-value="var(--eicui-base-color-success-100)"></div>
                        <div class="he-colorOption danger" style="background-color:var(--eicui-base-color-danger-100);" data-trigger="applyColorToText" data-value="var(--eicui-base-color-danger-100)"></div>
                        <div class="he-colorOption warning" style="background-color:var(--eicui-base-color-warning-100);" data-trigger="applyColorToText" data-value=var(--eicui-base-color-warning-100)"></div>
                        <div class="he-colorOption accent" style="background-color: var(--eicui-base-color-accent-100);" data-trigger="applyColorToText" data-value="var(--eicui-base-color-accent-100)"></div>
                        <div class="he-colorOption velvet" style="background-color: #55378c;" data-trigger="applyColorToText" data-value="#55378c"></div>
                        <div class="he-colorOption grey" style="background-color: #dcd8e7;" data-trigger="applyColorToText" data-value="#dcd8e7"></div>
                    </div>
                `,heImage: `
                    <button eicbutton xsmall type="button" class="tool-button medium icon-image he-addImg" data-tool="heImage" title="Add image" data-trigger="showImageSelector"  ${isSubmitted}></button>
                    <div id="he-imgSelectContainer" class="eicui-input-container he-imgSelectContainer" style="display:none;">  
                        <label xsmall for="he-imgSelect">Select an image:</label>
                        <select eicselect id="he-imgSelect" class="selects he-imgSelect"></select>
                        <label xsmall for="he-imgUrl">Add link to image? Add URL or Em@il:</label>
                    </div>
                `,
            heToken: `
                    <button eicbutton xsmall type="button" class="tool-button icon-loop he-addToken" data-tool="heToken" title="Add content variable" data-trigger="showTokenInput"  ${isSubmitted}></button>
                    <div id="he-tokenContainer" class="he-tokenContainer" style="display:none;">
                        <label small for="he-tokenText">You can write your own custom content variable in the text field below:</label>
                        <input eicinput small type="text" id="he-tokenText" name="he-tokenText" class="he-tokenText" placeholder="Enter content variable">
                        <label small"><b>OR</b></label>
                        <label small for="he-tokenSelect">Select a predefined content variable in the list below :</label>
                        <select eicselect small id="he-tokenSelect" name="he-tokenSelect" class="he-tokenSelect"></select>
                        </br>
                        <button eicbutton small class="info tool-button he-confirmAddToken" data-trigger="createToken">Add content variable</button>
                    </div>
                `
        };
        // Gen. HTML buttons
        toolButtonsContainer.innerHTML = availableButtons.map(btn => buttonTemplates[btn] || '').join('')
        
        this.attachButtonTriggers(toolButtonsContainer)
        this.toggleButtonsByFieldType(fieldType)
    } 
    
    
    setCursorToField(fieldType) {
        const field = this.el.querySelector(`.template-field.${fieldType}`);
        if (field && field.contentEditable !== "false") {
            field.focus();
        }
    }
    
    /*
    LISTENER
    */
    initEditorEvents() {
        const triggers = this.el.querySelectorAll('[data-trigger]');
        
        triggers.forEach(element => {
            const triggerMethods = element.dataset.trigger.split(',').map(method => method.trim());
            
            element.addEventListener('click', () => {
                const changeValue = element.dataset.value || null;
                const numericChange = (changeValue !== null && !isNaN(changeValue))
                ? parseFloat(changeValue)
                : changeValue;
                
                triggerMethods.forEach(triggerMethod => {
                    let method = this[triggerMethod];
                    
                    // 👇 Fallback vers externalHandlers si la méthode n'existe pas dans la classe
                    if (typeof method !== 'function' && this.externalHandlers) {
                        method = this.externalHandlers[triggerMethod];
                    }
                    
                    if (typeof method === 'function') {
                        method.call(this, numericChange); // on garde `this` comme contexte
                    } else {
                        console.error(`Method ${triggerMethod} doesn't exist`);
                    }
                });
            });
        });
    }
    
    attachButtonTriggers(container) {
        
        const triggers = container.querySelectorAll('[data-trigger]');
        
        triggers.forEach(element => {
            const triggerMethods = element.dataset.trigger.split(',').map(method => method.trim());
            
            element.addEventListener('click', () => {
                const changeValue = element.dataset.value || null;
                
                let numericChange = isNaN(changeValue) ? changeValue : parseFloat(changeValue);
                
                triggerMethods.forEach(triggerMethod => {
                    if (typeof this[triggerMethod] === 'function') {
                        this[triggerMethod](numericChange);
                    } else {
                        console.error(`Method ${triggerMethod} does not exist`);
                    }
                });
            });
        });
    }
    
    toggleButtonsByFieldType(fieldType) {
        const availableButtons = this.buttonMap[fieldType] || [];
        
        availableButtons.forEach(button => {
            const btnElement = this.el.querySelector(`.tpl-toolButtons .${button}`);
            if (btnElement) {
                btnElement.classList.remove('hidden');
            }
        });
    }
    
    isInsertionAllowed(range) {
        if (!range || !range.startContainer) return false
        
        let parentElement = null
        
        if (range.startContainer.nodeType === Node.ELEMENT_NODE) {
            parentElement = range.startContainer.closest('.template-field')
        } else if (range.startContainer.nodeType === Node.TEXT_NODE) {
            parentElement = range.startContainer.parentNode?.closest('.template-field')
        }
        
        return parentElement !== null
    }
    
    
    saveSelection() {
        const selection = window.getSelection()
        if (selection.rangeCount > 0) {
            this.savedRange = selection.getRangeAt(0).cloneRange()
            this.selectedText = selection.toString()
        }
    }
    
    restoreSelection() {
        if (this.savedRange) {
            const selection = window.getSelection()
            selection.removeAllRanges()
            selection.addRange(this.savedRange)
        }
    }
    
    saveState() {
        if (this.isUndoRedo) return
        const state = {
            subject: this.el.querySelector('.template-field.subject').innerHTML,
            header: this.el.querySelector('.template-field.header').innerHTML,
            main: this.el.querySelector('.template-field.main').innerHTML,
            footer: this.el.querySelector('.template-field.footer').innerHTML,
            altText: this.el.querySelector('.template-field.altText').innerHTML
        };
        this.undoStack.push(state)
        this.redoStack = []
    }
    
    restoreState(state) {
        this.el.querySelector('.template-field.subject').innerHTML = state.subject
        this.el.querySelector('.template-field.header').innerHTML = state.header
        this.el.querySelector('.template-field.main').innerHTML = state.main
        this.el.querySelector('.template-field.footer').innerHTML = state.footer
        this.el.querySelector('.template-field.altText').innerText = state.altText
    }
    
    undo() {
        if (this.undoStack.length > 1) {
            this.isUndoRedo = true
            const currentState = this.undoStack.pop()
            this.redoStack.push(currentState)
            const lastState = this.undoStack[this.undoStack.length - 1]
            this.restoreState(lastState)
            this.isUndoRedo = false
        }
    }
    
    redo() {
        if (this.redoStack.length > 0) {
            this.isUndoRedo = true
            const nextState = this.redoStack.pop()
            this.undoStack.push(nextState)
            this.restoreState(nextState)
            this.isUndoRedo = false
        }
    }
    
    //clear copy/paste content
    handlePaste(event) {
        event.preventDefault();
        const text = event.clipboardData.getData('text/plain');
        const range = window.getSelection().getRangeAt(0);
        range.deleteContents();
        range.insertNode(document.createTextNode(text));
    }
    
    /* Ensure not alternateTextEditor */
    isSelectionInsideAlternateTextEditor() {
        const alternateTextEditor = this.el.querySelector('.template-field.altText');
        const selection = window.getSelection();
        
        if (selection.rangeCount > 0) {
            const range = selection.getRangeAt(0);
            const selectedElement = range.commonAncestorContainer;
            
            // Check if selected content not in alternateTextEditor
            return alternateTextEditor && alternateTextEditor.contains(selectedElement);
        }
        return false;
    }
    
    /* MANAGE STYLES 
    Bold Underline Italic */
    toggleStyle(styleType) {
        if (this.isSelectionInsideAlternateTextEditor()) return;
        
        const selection = window.getSelection();
        
        if (selection.rangeCount > 0) {
            const range = selection.getRangeAt(0);
            const selectedText = range.toString();
            
            let isStyled = false;
            let parentStyledNode = null;
            let currentNode = range.startContainer;
            
            let tagName, styleProperty, styleValue;
            
            if (styleType === 'bold') {
                tagName = 'SPAN';
                styleProperty = 'fontWeight';
                styleValue = 'bold';
            } else if (styleType === 'italic') {
                tagName = 'EM';
                styleProperty = 'fontStyle';
                styleValue = 'italic';
            } else {
                tagName = 'U';
                styleProperty = 'textDecoration';
                styleValue = 'underline';
            }
            
            if (currentNode.nodeType === Node.TEXT_NODE) {
                currentNode = currentNode.parentNode;
            }
            
            while (currentNode && currentNode.nodeType !== Node.DOCUMENT_NODE) {
                if (currentNode.nodeType === Node.ELEMENT_NODE && currentNode.nodeName === tagName) {
                    if (currentNode.style[styleProperty] === styleValue) {
                        isStyled = true;
                        parentStyledNode = currentNode;
                        break;
                    }
                }
                currentNode = currentNode.parentNode;
            }
            
            if (isStyled) {
                const textNode = document.createTextNode(selectedText);
                if (parentStyledNode) {
                    parentStyledNode.parentNode.replaceChild(textNode, parentStyledNode);
                    selection.removeAllRanges();
                    selection.addRange(range);
                }
            } else {
                const element = document.createElement(tagName);
                element.style[styleProperty] = styleValue;
                
                range.deleteContents();
                range.insertNode(this.spaceAfter);
                range.insertNode(element);
                range.insertNode(this.spaceBefore);
                element.appendChild(document.createTextNode(selectedText));
                
                selection.removeAllRanges();
                const newRange = document.createRange();
                newRange.selectNodeContents(element);
                selection.addRange(newRange);
                
                this.saveState();
            }
        }
    }    
    
    applyTextAlignment(alignment) {
        
        if (this.isSelectionInsideAlternateTextEditor()) return;
        
        const selection = window.getSelection();
        if (!selection.rangeCount) return;
        
        const range = selection.getRangeAt(0);
        
        // Check if the cursor is inside a text node
        let blockElement = this.findBlockElement(range.startContainer);
        
        if (!blockElement) return;
        
        const isAligned = blockElement.style.textAlign === alignment;
        
        if (isAligned) {
            this.removeAlignment(blockElement);
        } else {
            this.applyAlignment(blockElement, alignment);
        }
        
        this.saveState();
    }
    
    applyAlignment(blockElement, alignment) {
        blockElement.style.textAlign = alignment;
    }
    
    removeAlignment(blockElement) {
        blockElement.style.textAlign = '';
    }
    findBlockElement(node) {
        while (node && node.nodeType !== Node.DOCUMENT_NODE) {
            if (node.nodeType === Node.ELEMENT_NODE && (node.nodeName === 'P' || node.nodeName === 'DIV')) {
                return node;
            }
            node = node.parentNode;
        }
        return null;
    }
    
    changeFontSize(change) {
        if (this.isSelectionInsideAlternateTextEditor()) return;
        
        const selection = window.getSelection();
        let targetSpan = null;
        
        if (selection.rangeCount) {
            const range = selection.getRangeAt(0);
            const selectedText = range.toString().trim();
            
            if (selectedText.length > 0) {
                let span = range.startContainer.parentNode;
                
                if (span.tagName === 'SPAN' && span.id.startsWith('highlighted-text-')) {
                    targetSpan = span;
                } else {
                    const uniqueId = `highlighted-text-${Date.now()}`;
                    span = document.createElement('span');
                    span.id = uniqueId;
                    span.classList.add('highlight');
                    range.surroundContents(span);
                    targetSpan = span;
                }
                
                this.lastModifiedSpan = targetSpan; 
            }
        }
        
        if (this.lastModifiedSpan) {
            const currentFontSize = window.getComputedStyle(this.lastModifiedSpan).getPropertyValue('font-size');
            const newFontSize = (parseFloat(currentFontSize) + change) + 'px';
            this.lastModifiedSpan.style.fontSize = newFontSize;
        }
        
        selection.removeAllRanges();
        this.saveState();
    }   
    
    //COLOR TEXT
    changeColor(color) {
        const selection = window.getSelection();
        if (!selection.rangeCount) return;
        
        const range = selection.getRangeAt(0);
        
        // Ensure alternateTextEditor is a valid node
        const alternateTextEditor = this.el.querySelector('.template-field.altText');
        if (!alternateTextEditor) return; // If the editor element doesn't exist, exit
        
        // Check if a node is within the alternate text editor
        const isNodeWithinEditor = (node) => {
            while (node) {
                if (node === alternateTextEditor) return true;
                node = node.parentNode;
            }
            return false;
        };
        
        if (isNodeWithinEditor(range.commonAncestorContainer)) {
            return; 
        }
        
        if (range.collapsed) return;
        
        // Create a span to apply the color
        const span = document.createElement('span');
        span.style.color = color;
        
        // Wrap the selected range with the span
        range.surroundContents(span);
        
        this.saveState();
    }
    
    /*MANAGE TABLE */
    showTableInput() {
        this.saveSelection();
        this.tableContainer = this.el.querySelector('.he-tableContainer');
        this.buttonRect = null;
        this.rowsInput = this.tableContainer.querySelector('.he-tableRows');
        this.colsInput = this.tableContainer.querySelector('.he-tableCols');
        this.borderCheckbox = this.tableContainer.querySelector('.he-addTableBorders');
        this.centerCheckbox = this.tableContainer.querySelector('.he-addTableCenter');
        const addTableButton = this.el.querySelector('.he-addTable');
        const isTableContainerVisible = window.getComputedStyle(this.tableContainer).display !== "none";
        
        // Reset the input values when opening
        this.rowsInput.value = '';
        this.colsInput.value = '';
        
        if (!isTableContainerVisible) {
            if (addTableButton) {
                this.buttonRect = addTableButton.getBoundingClientRect();
            }
            
            // Display the table input under the button
            this.tableContainer.style.display = 'block';
            this.tableContainer.style.position = 'fixed';
            this.tableContainer.style.border = '1px solid #ccc';
            this.tableContainer.style.padding = '10px';
            this.tableContainer.style.background = '#fff';
            this.tableContainer.style.zIndex = '999';
            
            const containerWidth = this.tableContainer.offsetWidth;
            
            const buttonRect = addTableButton.getBoundingClientRect();
            
            const topPosition = buttonRect.bottom + window.scrollY;
            const leftPosition = buttonRect.left + window.scrollX - containerWidth;
            
            this.tableContainer.style.top = `${topPosition}px`;
            this.tableContainer.style.left = `${leftPosition}px`;
            
            // Update button to "cancel" mode
            addTableButton.classList.remove("icon-table");
            addTableButton.classList.add("icon-cancel");
            addTableButton.setAttribute("title", "close");
        } else {
            this.closeTableInput();
        }
    }
    
    closeTableInput() {
        // Hide the table input
        this.tableContainer.style.display = "none";
        
        // Reset the button back to "add table" mode
        const addTableButton = this.el.querySelector('.he-addTable');
        addTableButton.classList.remove("icon-cancel");
        addTableButton.classList.add("icon-table");
        addTableButton.setAttribute("title", "add table");
        
        // Reset the button rect
        this.buttonRect = null;
        return
    }
    
    createTable() {
        this.restoreSelection();
        const numRows = parseInt(this.rowsInput.value) || 1;
        const numCols = parseInt(this.colsInput.value) || 1;
        const hasBorders = this.borderCheckbox.checked;
        const tabCenter = this.centerCheckbox.checked;
        
        // Validate inputs
        if (numRows < 1 || numCols < 1) {
            ui.growl.append('Please enter valid numbers for rows and columns.');
            return;
        }
        
        // Insert the table
        this.insertTable(numRows, numCols, hasBorders, tabCenter);
        this.closeTableInput();
    }
    
    insertTable(rows, cols, hasBorders, tabCenter) {
        const selection = window.getSelection();
        if (selection.rangeCount === 0) return;
        
        const range = selection.getRangeAt(0);
        
        if (!this.isInsertionAllowed(range)) {
            ui.growl.append('select a valid location', 'error');
            return;
        }
        
        // Créer l'élément table
        const tplTable = document.createElement('table');
        tplTable.classList.add('tpl-table');
        
        if (hasBorders) {
            tplTable.classList.add('tpl-table-bordered');
            tplTable.style.border = "1px solid #999";
            tplTable.style.borderCollapse = "collapse";
        }
        
        if (tabCenter) {
            tplTable.style.margin = "auto";
        }
        
        // Add rows and cols
        for (let i = 0; i < rows; i++) {
            const row = document.createElement('tr');
            for (let j = 0; j < cols; j++) {
                const cell = document.createElement('td');
                cell.innerHTML = '&nbsp;';
                
                if (hasBorders) {
                    cell.style.border = "1px solid #999";
                    tplTable.style.borderCollapse = "collapse";
                }
                
                row.appendChild(cell);
            }
            tplTable.appendChild(row);
        }
        
        // Insérer le tableau à la position du curseur
        range.deleteContents();
        range.insertNode(tplTable);
    }
    
    /*MANAGE COLORS */
    showColorPalette() {
        this.saveSelection();
        
        this.colorPalette = this.el.querySelector('.he-colorPalette');
        this.buttonRect = null;
        
        const colorTextButton = this.el.querySelector('.he-colorText');
        const isPaletteVisible = window.getComputedStyle(this.colorPalette).display !== "none";
        
        if (!isPaletteVisible) {
            this.buttonRect = colorTextButton.getBoundingClientRect();
            
            this.colorPalette.style.display = "flex";
            this.colorPalette.style.gridTemplateColumns = "repeat(auto-fill, minmax(50px, 1fr))";
            this.colorPalette.style.position = 'fixed';
            this.colorPalette.style.zIndex = '999';
            this.colorPalette.style.top = `${this.buttonRect.bottom + window.scrollY}px`;
            
            // Vérifie si le sélecteur dépasse la largeur de l'écran
            const paletteWidth = this.colorPalette.offsetWidth;
            const windowWidth = window.innerWidth;
            const defaultLeft = this.buttonRect.left + window.scrollX;
            
            if (defaultLeft + paletteWidth > windowWidth) {
                // Ouvrir vers la gauche
                this.colorPalette.style.left = `${defaultLeft - paletteWidth}px`;
            } else {
                // Ouvrir vers la droite (comportement par défaut)
                this.colorPalette.style.left = `${defaultLeft}px`;
            }
            
            colorTextButton.classList.remove("icon-format-color");
            colorTextButton.classList.add("icon-cancel");
            colorTextButton.setAttribute("title", "close");
        } else {
            this.closeColorPalette();
        }
    }
    
    
    closeColorPalette() {
        this.colorPalette.style.display = "none";
        
        const colorTextButton = this.el.querySelector('.he-colorText');
        colorTextButton.classList.remove("icon-cancel");
        colorTextButton.classList.add("icon-format-color");
        colorTextButton.setAttribute("title", "color text");
        
        this.buttonRect = null;
        return
    }
    
    applyColorToText(color) {
        this.restoreSelection();    
        if (!this.savedRange) {
            console.error('No selection saved to apply color');
            return;
        }
        const selection = window.getSelection();
        if (!selection.rangeCount) {
            console.error('No range found in selection');
            return;
        }
        
        const range = selection.getRangeAt(0);
        const selectedTextContent = range.extractContents();
        
        const spanColor = document.createElement('span');
        spanColor.style.color = color;
        spanColor.appendChild(selectedTextContent);
        
        if (range) {
            range.deleteContents();
            range.insertNode(this.spaceBefore);
            range.insertNode(spanColor);
            range.insertNode(this.spaceAfter);
        }
        
        window.getSelection().removeAllRanges();
        this.closeColorPalette();
    }
    
    /*MANAGE IMAGES SELECTOR*/
    async showImageSelector() {
        this.saveSelection()
        this.imgSelectContainer = this.el.querySelector('.he-imgSelectContainer')
        this.selectedImageUrl = "";
        this.linkInput = this.el.querySelector('.he-imgUrl')
        const addImageButton = this.el.querySelector('.he-addImg')
        const isImgContainerVisible = window.getComputedStyle(this.imgSelectContainer).display !== "none"
        
        if (!isImgContainerVisible) {
            this.selectedImageUrl = ""
            
            // Always reload images before showing the selector
            if (typeof this.context.templates?.getImages === 'function') {
                this.showLoading(addImageButton)
                this.images = await this.context.templates.getImages(this.context.templateId)
                
            }
            await this.generateImageSelector()
            
            this.imgSelectContainer.style.display = "block"
            this.imgSelectContainer.style.position = 'fixed'
            this.imgSelectContainer.style.border = '1px solid #ccc'
            this.imgSelectContainer.style.width = '20%'
            this.imgSelectContainer.style.padding = '10px'
            this.imgSelectContainer.style.background = '#fff'
            this.imgSelectContainer.style.zIndex = '999'
            this.imgSelectContainer.style.visibility = 'hidden'
            
            
            const containerWidth = this.imgSelectContainer.offsetWidth
            
            const buttonRect = addImageButton.getBoundingClientRect()
            
            const topPosition = buttonRect.bottom + window.scrollY
            const leftPosition = buttonRect.left + window.scrollX - containerWidth
            
            this.imgSelectContainer.style.top = `${topPosition}px`
            this.imgSelectContainer.style.left = `${leftPosition}px`
            
            this.imgSelectContainer.style.visibility = 'visible'
            
            addImageButton.classList.remove("icon-image")
            addImageButton.classList.add("icon-cancel")
            addImageButton.setAttribute("title", "close image selector")
            this.hideLoading(addImageButton, '')
            
        } else {
            this.closeImageSelector();
        }
    }
    
    closeImageSelector() {
        this.imgSelectContainer.style.display = "none";
        const addImgButton = this.el.querySelector('.he-addImg');
        if (addImgButton) {
            addImgButton.classList.remove("icon-cancel");
            addImgButton.classList.add("icon-image");
            addImgButton.setAttribute("title", "Add a picture");
        }
    }
    
    handleImageClick() {
        this.restoreSelection();
        if (!this.selectedImageUrl) {
            document.innerHTML = `<div eicalert danger>Selected an image</div>`;
            return;
        }
        this.insertImage(this.selectedImageUrl, this.selectedImageTitle, this.selectedImageId);
        this.closeImageSelector();
    }
    
    insertImage(url, title, id) {
        let selection = window.getSelection();
        
        if (!selection.rangeCount) {
            console.warn("No valid selection found.");
            return;
        }
        
        let range = selection.getRangeAt(0);
        let selectedNode = range.startContainer;
        let parentImage = selectedNode.nodeType === Node.ELEMENT_NODE && 
        (selectedNode.tagName === "IMG" || selectedNode.closest('.tpl-resizer'));
        
        if (parentImage) {
            range = document.createRange();
            range.setStartAfter(selectedNode.closest('.tpl-resizer'));
            range.setEndAfter(selectedNode.closest('.tpl-resizer'));
            selection.removeAllRanges();
            selection.addRange(range);
        }
        
        if (range.startContainer.nodeType === Node.TEXT_NODE) {
            range.setStartAfter(range.startContainer);
            range.setEndAfter(range.startContainer);
        }
        
        if (range.startContainer.nodeType === Node.ELEMENT_NODE &&
            range.startContainer.querySelector('.tpl-resizer')) {
                range.setStartAfter(range.startContainer.querySelector('.tpl-resizer'));
            }
            
            const container = document.createElement('div');
            container.className = 'tpl-resizer';
            
            const imgElement = document.createElement('img');
            imgElement.src = url;
            imgElement.id = id;
            imgElement.title = title;
            imgElement.alt = title;
            
            imgElement.onload = () => {
                const naturalWidth = imgElement.naturalWidth;
                const naturalHeight = imgElement.naturalHeight;
                container.style.maxWidth = `${naturalWidth}px`;
                container.style.maxHeight = `${naturalHeight}px`;
                imgElement.style.width = '100%';
                imgElement.style.height = 'auto';
            };
            
            container.appendChild(imgElement);
            
            const spaceAfter = document.createTextNode("\u00A0");
            
            this.linkValue = this.linkInput.value.trim();
            if (this.linkValue) {
                // Vérification si le lien est une adresse e-mail
                const isEmail = this.linkValue.startsWith('mailto:') || /^[\w.-]+@[\w.-]+\.\w+$/.test(this.linkValue);
                
                if (!this.linkValue.startsWith('http://') && !this.linkValue.startsWith('https://') && !isEmail) {
                    this.linkValue = 'http://' + this.linkValue;
                } else if (/^[\w.-]+@[\w.-]+\.\w+$/.test(this.linkValue)) {
                    this.linkValue = 'mailto:' + this.linkValue;
                }
                
                if (!this.validateURL(this.linkValue) && !isEmail) {
                    ui.growl.append('Invalid URL or email address', 'error');
                    return;
                }
                
                const linkElement = document.createElement('a');
                linkElement.href = this.linkValue;
                linkElement.target = isEmail ? "_self" : "_blank"; // Ouvrir les emails dans la même fenêtre
                
                linkElement.appendChild(container);
                
                range.insertNode(linkElement);
                range.insertNode(spaceAfter);
            } else {
                range.insertNode(container);
                range.insertNode(spaceAfter);
            }
            
            const newRange = document.createRange();
            newRange.setStartAfter(spaceAfter);
            newRange.setEndAfter(spaceAfter);
            selection.removeAllRanges();
            selection.addRange(newRange);
            
            document.dispatchEvent(new Event('insertImage'));
        }
        
        
        async generateImageSelector() {
            this.imgSelectContainer.innerHTML = "";
            
            // Preloaded Images Selector
            const imgSelect = document.createElement("div");
            imgSelect.className = "he-imgSelect";
            imgSelect.style.display = "flex";
            imgSelect.style.flexDirection = "column";
            imgSelect.style.maxHeight = "10em";
            imgSelect.style.overflowY = "auto";
            
            this.images = await this.images;
            const host = window.location.hostname;
            let envUrl = (host.split('.')[1] !== 'eismea') ? host.split('.')[1] + '.' : '';
            
            this.images.forEach(image => {
                const genUrl = `https://myeic.${envUrl}eismea.eu/public/images${image.object.path}/${image.object.name}`;
                
                const imgOption = document.createElement("div");
                imgOption.className = "he-imgItem";
                imgOption.style.display = "flex";
                imgOption.style.alignItems = "center";
                imgOption.style.padding = "5px";
                imgOption.style.cursor = "pointer";
                imgOption.dataset.url = genUrl;
                imgOption.dataset.id = image.object.name.replace(/\.[^/.]+$/, "");
                imgOption.dataset.title = image.object.title;
                
                const imgThumbnail = document.createElement("img");
                imgThumbnail.src = genUrl;
                imgThumbnail.alt = image.object.title;
                imgThumbnail.style.width = "100px";
                imgThumbnail.style.height = "auto";
                imgThumbnail.style.marginRight = "10px";
                
                const imgTitle = document.createElement("span");
                imgTitle.textContent = image.object.title;
                imgTitle.style.flexGrow = "1";
                
                const deleteButton = document.createElement("button");
                deleteButton.setAttribute("eicbutton", "");
                deleteButton.className = "icon-cancel delete-img";
                deleteButton.setAttribute("xxsmall", "");
                deleteButton.setAttribute("rounded", "");
                deleteButton.setAttribute("danger", "");
                deleteButton.setAttribute("type", "button");
                deleteButton.dataset.id = genUrl;
                deleteButton.dataset.trigger = "onDeleteImage";
                
                imgOption.appendChild(imgThumbnail);
                imgOption.appendChild(imgTitle);
                imgOption.appendChild(deleteButton);
                
                imgOption.addEventListener("click", () => {
                    this.selectedImageUrl = imgOption.dataset.url;
                    this.selectedImageTitle = imgOption.dataset.title;
                    this.selectedImageId = imgOption.dataset.id;
                    this.highlightSelectedImage(imgOption);
                });
                
                deleteButton.addEventListener("click", (event) => {
                    event.stopPropagation();
                    this.onDeleteImage(image.object.id, image.object.name, image.object.title);
                });
                
                imgSelect.appendChild(imgOption);
            });
            
            this.imgSelectContainer.appendChild(imgSelect);
            
            this.addUrlInputAndButton();
        }
        
        // Delete from MySQL database and s3 bucket
        async onDeleteImage(imgId, imgName, imgTitle) {
            const host = window.location.hostname
            let envUrl = (host.split('.')[1] !== 'eismea') ? host.split('.')[1] + '.' : ''
            let deleteUrl = `https://myeic.${envUrl}eismea.eu/public/images/common/${imgName}`
            
            let result = await this.context.confirmDialog({
                title: 'DELETE template ?',
                message: `<p>You are about to permanently delete the image "<b>${imgTitle}</b>".</p>
                      <p>Are you sure?</p>`,
                okLabel: 'Delete',
                severity: 'danger',
                okPromise: async () => {    
                    await this.context.templates.deleteImage(imgId, deleteUrl);
                }
            });
            if(result) {
                ui.growl.append("Image deleted !", 'success')
                // Hide the image item in the selector
                const imgItem = this.el.querySelector(`.he-imgItem[data-id="${imgId}"]`)
                if (imgItem) imgItem.style.display = 'none'
            } else { 
                ui.growl.append("Error deleting Image!", 'error') 
            }
        }       
        
        highlightSelectedImage(selectedOption) {
            const imgItems = this.imgSelectContainer.querySelectorAll('.he-imgItem');
            imgItems.forEach(item => {
                item.style.backgroundColor = "";
            });
            selectedOption.style.backgroundColor = "#e0e0e0";
        }
        
        addUrlInputAndButton() {
            const imgUrlLabel = document.createElement('h5');
            imgUrlLabel.setAttribute('for', 'he-imgUrl');
            imgUrlLabel.setAttribute('xsmall', '');
            imgUrlLabel.setAttribute('primary', '');
            imgUrlLabel.textContent = "Optional - Add a link to the image:";
            
            const imgUrlInput = document.createElement('input');
            imgUrlInput.setAttribute('eicinput','');
            imgUrlInput.setAttribute('small', '');
            imgUrlInput.id = 'he-imgUrl';
            imgUrlInput.name = 'he-imgUrl';
            imgUrlInput.placeholder = 'Enter url or em@il (optional)';
            this.linkInput = imgUrlInput;
            
            const addButton = document.createElement('button');
            addButton.setAttribute('eicbutton', '');
            addButton.setAttribute('xsmall', '');
            addButton.setAttribute('primary', '');
            addButton.className = 'tool-button he-confirmAddImg';
            addButton.textContent = 'Add image';
            addButton.addEventListener('click', () => this.handleImageClick());
            
            this.imgSelectContainer.appendChild(imgUrlLabel);
            this.imgSelectContainer.appendChild(imgUrlInput);
            this.imgSelectContainer.appendChild(addButton);
        }
        
        /*MANAGE LINKS */
        showLinkInput() {
            this.saveSelection();
            this.linkContainer = this.el.querySelector('.he-linkContainer');
            this.linkUrlInput = this.el.querySelector('.he-linkUrl');
            this.linkTextInput = this.el.querySelector('.he-linkText');
            this.selectedText = '';
            this.selectedRange = null;
            this.addLinkButton = this.el.querySelector('.he-addLink');
            const selection = window.getSelection();
            const isLinkContainerVisible = window.getComputedStyle(this.linkContainer).display !== "none";
            
            if (!isLinkContainerVisible) {
                if (selection.rangeCount > 0 && !selection.isCollapsed) {
                    // Text is selected
                    this.selectedRange = selection.getRangeAt(0);
                    this.selectedText = this.selectedRange.toString();
                    this.linkTextInput.style.display = 'none';  // Hide the text input since text is already selected
                } else {
                    // No text selected, show input for link text
                    this.selectedText = '';
                    this.linkTextInput.style.display = 'block';  // Show the input to enter the link text
                }
                
                const buttonRect = this.addLinkButton.getBoundingClientRect();
                
                this.linkContainer.style.display = 'block';
                this.linkContainer.style.position = 'fixed';
                this.linkContainer.style.border = '1px solid #ccc';
                this.linkContainer.style.padding = '10px';
                this.linkContainer.style.background = '#fff';
                this.linkContainer.style.zIndex = 1000;
                
                // Div on left side of button
                const containerWidth = this.linkContainer.offsetWidth;
                
                this.linkContainer.style.top = `${buttonRect.bottom + window.scrollY}px`; 
                this.linkContainer.style.left = `${buttonRect.left + window.scrollX - containerWidth}px`;
                
                this.linkUrlInput.value = '';
                this.linkTextInput.value = '';  // Clear the text input in case it was used before
                this.linkUrlInput.focus();
                
                this.addLinkButton.classList.remove("icon-link");
                this.addLinkButton.classList.add("icon-cancel");
                this.addLinkButton.setAttribute("title", "close add link");
                
                window.addEventListener('scroll', this.updateLinkContainerPosition.bind(this));
            } else {
                this.closeLinkInput();
            }
        }
        
        updateLinkContainerPosition() {
            const buttonRect = this.addLinkButton.getBoundingClientRect();
            const containerWidth = this.linkContainer.offsetWidth;
            
            this.linkContainer.style.top = `${buttonRect.bottom + window.scrollY}px`;
            this.linkContainer.style.left = `${buttonRect.left + window.scrollX - containerWidth}px`;
        }
        
        
        
        validateURL(url) {
            const pattern = new RegExp('^(https?:\\/\\/)?' +
                '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' +
                '((\\d{1,3}\\.){3}\\d{1,3}))' +
                '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' +
                '(\\?[;&a-z\\d%_.~+=-]*)?' +
                '(\\#[-a-z\\d_]*)?$', 'i');
                return !!pattern.test(url);
            }
            
            createLink() {
                this.restoreSelection();
                
                this.linkUrlInput = this.el.querySelector('.he-linkUrl');
                let url = this.linkUrlInput.value.trim();
                
                const selection = window.getSelection();
                if (selection.rangeCount === 0) return; 
                
                const range = selection.getRangeAt(0);
                const text = this.selectedText || this.linkTextInput.value.trim(); // Use selected text
                
                if (!url || !text) {
                    ui.growl.append('Both URL and link text are required to create a link', 'error');
                    return;
                }
                
                // Check if mail adress (mailto:)
                const isEmail = url.startsWith('mailto:') || /^[\w.-]+@[\w.-]+\.\w+$/.test(url);
                
                // Add "mailto:" if e-mail without mailto
                if (!url.startsWith('http://') && !url.startsWith('https://') && !isEmail) {
                    url = 'http://' + url;
                } else if (/^[\w.-]+@[\w.-]+\.\w+$/.test(url)) {
                    url = 'mailto:' + url;
                }
                
                // Check URL
                if (!this.validateURL(url) && !isEmail) {
                    ui.growl.append('Invalid URL or email address', 'error');
                    return;
                }
                
                if (!this.isInsertionAllowed(range)) {
                    ui.growl.append('Select a valid location', 'error');
                    return;
                }
                
                const linkElement = document.createElement('a');
                linkElement.href = url;
                linkElement.target = isEmail ? '_self' : '_blank'; // mailto: open in same page
                linkElement.title = url;
                linkElement.alt = url;
                linkElement.textContent = text;
                
                if (this.savedRange) {
                    this.savedRange.deleteContents();
                    this.savedRange.insertNode(linkElement);
                } else {
                    // Insérer à la position du curseur
                    const range = window.getSelection().getRangeAt(0);
                    range.insertNode(this.spaceBefore);
                    range.insertNode(linkElement);
                    range.insertNode(this.spaceAfter);
                }
                
                window.getSelection().removeAllRanges();
                this.closeLinkInput();
            }
            
            
            closeLinkInput() {
                this.linkContainer.style.display = 'none';
                this.addLinkButton.classList.remove("icon-cancel");
                this.addLinkButton.classList.add("icon-link");
                this.addLinkButton.setAttribute("title", "add link");
            }
            
            /*MANAGE LIST */
            showListSelector() {
                this.saveSelection();
                
                this.listContainer = this.el.querySelector('.he-addListContainer');
                this.listItemsInput = this.el.querySelector('.he-listItems');
                
                const addListButton = this.el.querySelector('.he-addList');
                const isListContainerVisible = window.getComputedStyle(this.listContainer).display !== "none";
                
                // Reset the input value when opening
                this.listItemsInput.value = '';
                
                if (!isListContainerVisible) {
                    
                    const buttonRect = addListButton.getBoundingClientRect();
                    
                    
                    // Display the list selector under the button
                    this.listContainer.style.display = "block";
                    this.listContainer.style.position = 'fixed';
                    this.listContainer.style.border = '1px solid #ccc';
                    this.listContainer.style.padding = '10px';
                    this.listContainer.style.background = '#fff';
                    
                    const containerWidth = this.listContainer.offsetWidth;
                    
                    this.listContainer.style.top = `${buttonRect.bottom + window.scrollY}px`; 
                    this.listContainer.style.left = `${buttonRect.left + window.scrollX - containerWidth}px`;
                    
                    // Update button to "cancel" mode
                    addListButton.classList.remove("icon-list-ul");
                    addListButton.classList.add("icon-cancel");
                    addListButton.setAttribute("title", "close");
                } else {
                    this.closeListSelector();
                }
            }
            
            closeListSelector() {
                const listSelectContainer = this.listContainer;
                const addListButton = this.el.querySelector('.he-addList');
                
                // Hide the list selector
                listSelectContainer.style.display = "none";
                
                // Reset the button back to "add list" mode
                addListButton.classList.remove("icon-cancel");
                addListButton.classList.add("icon-list-ul");
                addListButton.setAttribute("title", "add list items");
                
                // Reset the button rect
                this.buttonRect = null;
            }
            
            confirmList() {
                this.restoreSelection();
                const listItemsTextarea = this.el.querySelector('.he-listItems');
                const listItems = listItemsTextarea.value.trim().split('\n');
                
                if (listItems.length === 0 || (listItems.length === 1 && listItems[0] === '')) {
                    alert("Please enter at least one item for the list.");
                    return;
                }
                
                let listType;
                if (this.el.querySelector('.he-listTypeBullet').checked) {
                    listType = 'bullet';
                } else if (this.el.querySelector('.he-listTypeDash').checked) {
                    listType = 'dash';
                } else if (this.el.querySelector('.he-listTypeNumbered').checked) {
                    listType = 'numbered';
                }
                
                this.insertList(listItems, listType);
                
                listItemsTextarea.value = '';
                
                this.closeListSelector();
            }
            
            getListType() {
                const bulletType = this.listContainer.querySelector('.he-listTypeBullet').checked;
                const dashType = this.listContainer.querySelector('.he-listTypeDash').checked;
                const numberedType = this.listContainer.querySelector('.he-listTypeNumbered').checked;
                
                if (bulletType) return 'bullet';
                if (dashType) return 'dash';
                if (numberedType) return 'numbered';
                return 'bullet';
            }
            
            insertList(items, type) {
                const selection = window.getSelection();
                if (selection.rangeCount === 0) return; 
                const range = selection.getRangeAt(0);
                
                if (!this.isInsertionAllowed(range)) {
                    ui.growl.append('select a valid location', 'error');
                    return;
                }
                
                // Check if insert in authorized fields
                let editor = range.commonAncestorContainer;
                while (editor && editor.nodeType !== Node.ELEMENT_NODE) {
                    editor = editor.parentNode;
                }
                
                if (!editor || (!editor.classList.contains('template-field.main'))) {
                    editor = this.el.querySelector('.template-field.main');
                }
                
                // Create list elements
                let heList;
                if (type === 'bullet' || type === 'dash') {
                    heList = document.createElement('ul');
                    if (type === 'dash') {
                        heList.style.listStyleType = 'none';
                    }
                } else if (type === 'numbered') {
                    heList = document.createElement('ol');
                }
                heList.style.marginLeft = '1em';
                heList.style.paddingLeft = '1em';
                
                // Add items
                items.forEach(item => {
                    const li = document.createElement('li');
                    if (type === 'dash') {
                        li.textContent = `- ${item}`;
                    } else {
                        li.textContent = item;
                    }
                    heList.appendChild(li);
                });
                
                // Insert list at cursor position
                if (range) {
                    range.deleteContents();
                    range.insertNode(heList);
                } else {
                    editor.appendChild(heList);
                }
            }
            
            /*MANAGE TOKENS */
            showTokenInput() {
                this.saveSelection();
                
                this.tokenTextInput = this.el.querySelector('.he-tokenText');
                this.tokenSelect = this.el.querySelector('.he-tokenSelect');
                this.tokenContainer = this.el.querySelector('.he-tokenContainer');
                this.addTokenButton = this.el.querySelector('.he-addToken');
                this.selectedText = '';
                this.savedRange = null;
                
                const selection = window.getSelection();
                const isTokenContainerVisible = window.getComputedStyle(this.tokenContainer).display !== "none";
                
                if (!isTokenContainerVisible) {
                    
                    if (selection.rangeCount > 0 && !selection.isCollapsed) {
                        // Selected text
                        this.savedRange = selection.getRangeAt(0);
                        this.selectedText = this.savedRange.toString().trim();
                        this.tokenTextInput.style.display = 'none';
                        this.tokenSelect.style.display = 'none';
                    } else {
                        this.populateTokenSelect();
                        this.selectedText = '';
                        this.savedRange = selection.getRangeAt(0);
                        this.tokenTextInput.style.display = 'block';
                        this.tokenSelect.style.display = 'block';
                    }
                    
                    const buttonRect = this.addTokenButton.getBoundingClientRect();
                    
                    this.tokenContainer.style.display = 'block';
                    this.tokenContainer.style.position = 'fixed';
                    this.tokenContainer.style.border = '1px solid #ccc';
                    this.tokenContainer.style.padding = '10px';
                    this.tokenContainer.style.background = '#fff';
                    this.tokenContainer.style.zIndex = 1000;
                    
                    const containerWidth = this.tokenContainer.offsetWidth;
                    
                    this.tokenContainer.style.top = `${buttonRect.bottom + window.scrollY}px`; 
                    this.tokenContainer.style.left = `${buttonRect.left + window.scrollX - containerWidth}px`;
                    
                    this.tokenTextInput.value = '';
                    this.tokenTextInput.focus();
                    
                    this.addTokenButton.classList.remove("icon-loop");
                    this.addTokenButton.classList.add("icon-cancel");
                    this.addTokenButton.setAttribute("title", "close Add variable");
                    
                } else {
                    this.closeTokenInput();
                }
            }
            
            async  populateTokenSelect() {
                this.tokenSelect.innerHTML = ""; 
                
                const defaultOption = document.createElement('option');
                defaultOption.value = '';
                defaultOption.text = 'Choose a replacement variable';
                this.tokenSelect.appendChild(defaultOption);
                
                // Add tokens list
                const tokens = await this.tokens;
                
                tokens.forEach(token => {
                    const option = document.createElement('option');
                    option.value = token.name;
                    option.text = token.name;
                    this.tokenSelect.appendChild(option);
                });
                
            }
            
            createToken() {
                this.restoreSelection()
                
                document.querySelectorAll('.caret-holder').forEach(el => el.remove())
                
                let tokenText = this.selectedText || this.tokenTextInput.value.trim()
                
                const selection = window.getSelection()
                if (selection.rangeCount === 0) return
                
                const range = selection.getRangeAt(0)
                
                const selectedToken = this.el.querySelector('.he-tokenSelect').value
                if (!tokenText && selectedToken) {
                    tokenText = selectedToken
                }
                
                if (!tokenText) {
                    ui.growl.append('Required text for variables', 'error')
                    return
                }
                
                if (!this.isInsertionAllowed(range)) {
                    ui.growl.append('select a valid location', 'error')
                    return
                }
                
                let parentTemplateField = null
                
                if (range.startContainer.nodeType === Node.ELEMENT_NODE) {
                    parentTemplateField = range.startContainer.closest('.template-field')
                } else if (range.startContainer.nodeType === Node.TEXT_NODE) {
                    parentTemplateField = range.startContainer.parentNode?.closest('.template-field')
                }
                if (!parentTemplateField) {
                    ui.growl.append('Select a valid location !', 'error')
                    return
                }
                
                const tokenElement = document.createElement('span')
                tokenElement.classList.add('tpl-token')
                tokenElement.setAttribute('eicchip', '')
                tokenElement.setAttribute('success', '')
                tokenElement.setAttribute('data-original', tokenText)
                tokenElement.textContent = tokenText
                
                const caretHolder = document.createElement('span')
                caretHolder.className = 'caret-holder'
                caretHolder.contentEditable = 'true'
                caretHolder.innerHTML = '&#8203;'
                
                const spaceBefore = document.createTextNode('\u00A0') // &nbsp;
                const spaceAfter = document.createTextNode('\u00A0')  // &nbsp.
                
                if (range) {
                    const fragment = document.createDocumentFragment()
                    fragment.appendChild(spaceBefore)
                    fragment.appendChild(tokenElement)
                    fragment.appendChild(spaceAfter)
                    fragment.appendChild(caretHolder)
                    
                    range.deleteContents()
                    range.insertNode(fragment)
                }
                
                this.tokenInserted = true
                
                this.tokenSelect.value = ''
                this.closeTokenInput()
            }
            
            
            closeTokenInput() {
                this.tokenContainer.style.display = 'none'
                
                this.addTokenButton.classList.remove("icon-cancel")
                this.addTokenButton.classList.add("icon-loop")
                this.addTokenButton.setAttribute("title", "Add content variable")
                
                if (this.tokenInserted) {
                    const caretHolder = document.querySelector('.caret-holder')
                    if (caretHolder) {
                        const range = document.createRange()
                        range.setStart(caretHolder, 1)
                        range.collapse(true)
                        
                        const sel = window.getSelection()
                        sel.removeAllRanges()
                        sel.addRange(range)
                    }
                } else {
                    this.restoreSelection()
                }
                
                this.tokenInserted = false;
            }
            // Add style into document head
            injectStyles() {
                const style = document.createElement('style');
                style.innerHTML = `
            .resize-container {
                position: relative;
                display: inline-block;
            }
            .tpl-resizer {
                resize: both;
                overflow: hidden;
                display: inline-block;
                max-width: 100%;
            }
            .he-imgItem.selected {
                border: 2px solid blue;
                background-color: lightgray;
            }
            .he-imgItem {
                transition: background-color 0.3s ease;
            }
            .he-imgItem:hover {
                background-color: #f0f0f0; 
            }
            .he-color-palette {
                display: grid;
                grid-template-columns: repeat(3, 1.5em);
                gap: 0.5em;
                position: fixed;
                border: 1px solid #ccc;
                padding: 2px;
                background-color: #fff;
                z-index: 1000;
            }
            .he-colorOption {
                width: 1.5em;
                height: 1.5em;
                cursor: pointer;
                pointer-events: auto;
            }
            .he-colorOption:hover {
                border: 2px solid #000;
            }
            .tpl-table {
                border-collapse: collapse;
            }
                
            tpl-table td {
                border: 1px solid #ccc;
                padding: 10px;
                position: relative;
            }
            .he-listItems{
                min-height: 100px;
            }
        `;
                document.head.appendChild(style);
            }
        }