/** * Layout Manager Module * จัดการการแสดงผลและการจัดการโครงสร้าง DOM */ (function(global) { 'use strict'; /** * คลาส LayoutManager * ให้ความสามารถในการจัดการโครงสร้าง DOM และการแสดงผล */ class LayoutManager { constructor(editor) { this.editor = editor; this.layoutTree = null; this.selectedElement = null; this.isResizing = false; this.resizeHandle = null; this.resizeStartX = 0; this.resizeStartY = 0; this.resizeStartWidth = 0; this.resizeStartHeight = 0; } /** * เริ่มต้นโมดูลจัดการเลย์เอาต์ */ init() { this.setupEventListeners(); this.buildLayoutTree(); if (this.editor.config.debug) { console.log('LayoutManager เริ่มต้นแล้ว'); } } /** * ตั้งค่า event listeners */ setupEventListeners() { // ฟังเหตุการณ์การเลือกอิลิเมนต์ this.editor.on('element:selected', (data) => { this.selectElement(data.element); }); // ฟังเหตุการณ์การเปลี่ยนแปลงโหมดตัวแก้ไข this.editor.on('editor:mode-changed', (data) => { if (data.mode === 'edit') { this.showLayoutPanel(); } else { this.hideLayoutPanel(); } }); // ฟังเหตุการณ์การวางคอมโพเนนต์ this.editor.on('dragdrop:component-dropped', () => { this.buildLayoutTree(); }); // ฟังเหตุการณ์การวางอิลิเมนต์ this.editor.on('dragdrop:element-dropped', () => { this.buildLayoutTree(); }); } /** * สร้างต้นไม้เลย์เอาต์ */ buildLayoutTree() { this.layoutTree = document.getElementById('editor-layout-tree'); if (!this.layoutTree) return; // ล้างต้นไม้เก่า this.layoutTree.innerHTML = ''; // สร้างต้นไม้ใหม่ this.buildLayoutTreeRecursive(this.editor.container, this.layoutTree, 0); } /** * สร้างต้นไม้เลย์เอาต์แบบเรียกซ้ำ */ buildLayoutTreeRecursive(element, parent, level) { // สร้าง ID สำหรับอิลิเมนต์ if (!element.getAttribute('data-element-id')) { element.setAttribute('data-element-id', 'element-' + Math.random().toString(36).substr(2, 9)); } const elementId = element.getAttribute('data-element-id'); // สร้างรายการต้นไม้ const item = this.editor.domUtils.createElement('div', { 'class': 'editor-layout-tree-item', 'data-element-id': elementId, 'style': `padding-left: ${level * 20}px` }); // สร้างชื่อแท็ก const tagName = element.tagName.toLowerCase(); const className = element.className ? '.' + element.className.split(' ').join('.') : ''; const name = this.editor.domUtils.createElement('span', { 'class': 'tree-element-name' }, `${tagName}${className}`); // สร้างไอคอน const icon = this.editor.domUtils.createElement('i', { 'class': 'material-icons tree-icon' }, this.getElementIcon(element)); // สร้างปุ่มดำเนินการ const actions = this.editor.domUtils.createElement('div', { 'class': 'tree-actions' }); const selectBtn = this.editor.domUtils.createElement('button', { 'class': 'tree-action-btn', 'title': 'เลือก' }, 'edit'); const visibilityBtn = this.editor.domUtils.createElement('button', { 'class': 'tree-action-btn', 'title': element.style.display === 'none' ? 'แสดง' : 'ซ่อน' }, `${element.style.display === 'none' ? 'visibility_off' : 'visibility'}`); const moveUpBtn = this.editor.domUtils.createElement('button', { 'class': 'tree-action-btn', 'title': 'ย้ายขึ้น' }, 'keyboard_arrow_up'); const moveDownBtn = this.editor.domUtils.createElement('button', { 'class': 'tree-action-btn', 'title': 'ย้ายลง' }, 'keyboard_arrow_down'); const deleteBtn = this.editor.domUtils.createElement('button', { 'class': 'tree-action-btn', 'title': 'ลบ' }, 'delete'); actions.appendChild(selectBtn); actions.appendChild(visibilityBtn); actions.appendChild(moveUpBtn); actions.appendChild(moveDownBtn); actions.appendChild(deleteBtn); // เพิ่มอิลิเมนต์ในรายการ item.appendChild(icon); item.appendChild(name); item.appendChild(actions); // เพิ่มรายการในพาเรนต์ parent.appendChild(item); // เพิ่ม event listeners selectBtn.addEventListener('click', () => { this.selectElement(element); }); visibilityBtn.addEventListener('click', () => { if (element.style.display === 'none') { element.style.display = ''; visibilityBtn.innerHTML = 'visibility'; } else { element.style.display = 'none'; visibilityBtn.innerHTML = 'visibility_off'; } }); moveUpBtn.addEventListener('click', () => { this.moveElementUp(element); }); moveDownBtn.addEventListener('click', () => { this.moveElementDown(element); }); deleteBtn.addEventListener('click', () => { this.deleteElement(element); }); // สร้างรายการย่อยสำหรับอิลิเมนต์ลูก const children = Array.from(element.children); if (children.length > 0) { const childrenContainer = this.editor.domUtils.createElement('div', { 'class': 'tree-children' }); children.forEach(child => { this.buildLayoutTreeRecursive(child, childrenContainer, level + 1); }); parent.appendChild(childrenContainer); } } /** * รับไอคอนสำหรับอิลิเมนต์ */ getElementIcon(element) { const tagName = element.tagName.toLowerCase(); switch (tagName) { case 'header': return 'header'; case 'footer': return 'footer'; case 'nav': return 'menu'; case 'section': return 'view_module'; case 'article': return 'article'; case 'div': return 'crop_square'; case 'img': return 'image'; case 'p': return 'text_fields'; case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': return 'title'; case 'ul': case 'ol': return 'list'; case 'li': return 'label'; case 'a': return 'link'; case 'button': return 'touch_app'; case 'form': return 'input'; case 'input': case 'textarea': case 'select': return 'text_format'; default: return 'code'; } } /** * เลือกอิลิเมนต์ */ selectElement(element) { this.selectedElement = element; // ลบการเลือกก่อนหน้า const previousSelected = this.layoutTree.querySelectorAll('.tree-selected'); previousSelected.forEach(el => { el.classList.remove('tree-selected'); }); // เลือกอิลิเมนต์ใหม่ในต้นไม้ const treeElement = this.layoutTree.querySelector(`[data-element-id="${element.getAttribute('data-element-id') || ''}"]`); if (treeElement) { treeElement.classList.add('tree-selected'); } // ส่งเหตุการณ์ this.editor.emit('layout:element-selected', {element}); } /** * แสดงแผงจัดการเลย์เอาต์ */ showLayoutPanel() { this.editor.uiManager.showPanel('layout'); this.buildLayoutTree(); } /** * ซ่อนแผงจัดการเลย์เอาต์ */ hideLayoutPanel() { this.editor.uiManager.hidePanel('layout'); } /** * ย้ายอิลิเมนต์ขึ้น */ moveElementUp(element) { const previousSibling = element.previousElementSibling; if (previousSibling) { element.parentNode.insertBefore(element, previousSibling); this.buildLayoutTree(); this.editor.emit('layout:element-moved', {element, direction: 'up'}); } } /** * ย้ายอิลิเมนต์ลง */ moveElementDown(element) { const nextSibling = element.nextElementSibling; if (nextSibling) { element.parentNode.insertBefore(nextSibling, element); this.buildLayoutTree(); this.editor.emit('layout:element-moved', {element, direction: 'down'}); } } /** * ลบอิลิเมนต์ */ deleteElement(element) { if (confirm('คุณแน่ใจหรือไม่ว่าต้องการลบอิลิเมนต์นี้?')) { element.remove(); this.buildLayoutTree(); this.editor.emit('layout:element-deleted', {element}); } } } // เปิดเผยคลาส LayoutManager ทั่วโลก global.LayoutManager = LayoutManager; })(typeof window !== 'undefined' ? window : this);