/**
* 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);