const editorHandler = (() => {
let editorChannels = [];
let selectedChannelId = null;
let selectedRowIds = new Set();
let currentGroupFilter = '';
let currentSort = { column: null, direction: 'asc' };
let sortableInstance = null;
let groupOrder = [];
const dom = {};
function cacheDom() {
const modal = document.getElementById('editorModal');
if (!modal) return false;
dom.modal = modal;
dom.tableContainer = modal.querySelector('#editor-table-container');
dom.tableBody = modal.querySelector('#editor-table-body');
dom.selectAllCheckbox = modal.querySelector('#editor-select-all');
dom.searchInput = modal.querySelector('#editor-search-input');
dom.groupFilterSelect = modal.querySelector('#editor-group-filter');
dom.fileNameDisplay = modal.querySelector('#file-name-display');
dom.editorPanel = modal.querySelector('#editor-panel');
dom.editorPlaceholder = modal.querySelector('#editor-placeholder');
dom.editorFormContent = modal.querySelector('#editor-form-content');
dom.editorChannelNameInput = modal.querySelector('#editor-channel-name');
dom.editorChannelTvgIdInput = modal.querySelector('#editor-channel-tvg-id');
dom.editorChannelChNumInput = modal.querySelector('#editor-channel-ch-num');
dom.editorChannelLogoInput = modal.querySelector('#editor-channel-logo');
dom.editorLogoPreview = modal.querySelector('#editor-logo-preview');
dom.editorChannelUrlInput = modal.querySelector('#editor-channel-url');
dom.editorChannelGroupInput = modal.querySelector('#editor-channel-group');
dom.groupSuggestionsDatalist = modal.querySelector('#group-suggestions');
dom.editorFavCheckbox = modal.querySelector('#editor-fav-channel');
dom.editorHideChannelCheckbox = modal.querySelector('#editor-hide-channel');
dom.editorKodiLicenseTypeInput = modal.querySelector('#editor-kodi-license-type');
dom.editorKodiLicenseKeyInput = modal.querySelector('#editor-kodi-license-key');
dom.editorKodiStreamHeadersInput = modal.querySelector('#editor-kodi-stream-headers');
dom.editorVlcUserAgentInput = modal.querySelector('#editor-vlc-user-agent');
dom.editorSaveBtn = modal.querySelector('#editor-save-btn');
dom.editorPlayBtn = modal.querySelector('#editor-play-btn');
dom.editorDeleteBtn = modal.querySelector('#editor-delete-btn');
dom.closeEditorBtn = modal.querySelector('#close-editor-btn');
dom.multiEditBtn = modal.querySelector('#multi-edit-btn');
dom.deleteSelectedBtn = modal.querySelector('#delete-selected-btn');
dom.clearSelectionBtn = modal.querySelector('#clear-selection-btn');
const multiEditModal = document.getElementById('multiEditModal');
dom.multiEditModal = multiEditModal;
dom.multiEditChannelCount = multiEditModal.querySelector('#multiEditChannelCount');
dom.multiEditEnableGroup = multiEditModal.querySelector('#multiEditEnableGroup');
dom.multiEditGroupInput = multiEditModal.querySelector('#multiEditGroupInput');
dom.multiEditEnableFavorite = multiEditModal.querySelector('#multiEditEnableFavorite');
dom.multiEditFavoriteSelect = multiEditModal.querySelector('#multiEditFavoriteSelect');
dom.multiEditEnableHidden = multiEditModal.querySelector('#multiEditEnableHidden');
dom.multiEditHiddenSelect = multiEditModal.querySelector('#multiEditHiddenSelect');
dom.multiEditEnableUserAgent = multiEditModal.querySelector('#multiEditEnableUserAgent');
dom.multiEditUserAgentInput = multiEditModal.querySelector('#multiEditUserAgentInput');
dom.multiEditEnableStreamHeaders = multiEditModal.querySelector('#multiEditEnableStreamHeaders');
dom.multiEditStreamHeadersInput = multiEditModal.querySelector('#multiEditStreamHeadersInput');
dom.multiEditStreamHeadersMode = multiEditModal.querySelector('#multiEditStreamHeadersMode');
dom.applyMultiEditBtn = multiEditModal.querySelector('#applyMultiEditBtn');
return true;
}
function init(channelsData, fileName) {
if (!cacheDom()) {
console.error("Editor DOM not found. Cannot initialize.");
return;
}
editorChannels = JSON.parse(JSON.stringify(channelsData));
editorChannels.forEach((ch, idx) => {
if (ch) {
ch.editorId = `editor-ch-${idx}-${Date.now()}`;
}
});
dom.fileNameDisplay.textContent = fileName || "Lista Actual";
dom.fileNameDisplay.classList.add('loaded');
updateGroupOrder();
renderTable();
bindEvents();
showEditorPlaceholder();
clearMultiSelection();
}
function bindEvents() {
if (dom.editorSaveBtn.dataset.initialized) return;
dom.editorSaveBtn.addEventListener('click', handleEditorSave);
dom.editorPlayBtn.addEventListener('click', handleEditorPlay);
dom.editorDeleteBtn.addEventListener('click', handleEditorDelete);
dom.closeEditorBtn.addEventListener('click', showEditorPlaceholder);
dom.tableBody.addEventListener('click', handleTableBodyClick);
dom.selectAllCheckbox.addEventListener('change', handleSelectAllVisible);
dom.tableBody.addEventListener('change', handleRowCheckboxChange);
dom.searchInput.addEventListener('input', debounce(() => { currentSort.column = null; renderTable(); }, 300));
dom.groupFilterSelect.addEventListener('change', (e) => { currentGroupFilter = e.target.value; renderTable(); });
dom.deleteSelectedBtn.addEventListener('click', deleteSelectedChannels);
dom.clearSelectionBtn.addEventListener('click', clearMultiSelection);
dom.multiEditBtn.addEventListener('click', openMultiEditModal);
dom.modal.querySelectorAll('th.sortable').forEach(th => {
th.addEventListener('click', () => handleSort(th.dataset.sort));
});
bindMultiEditEvents();
dom.editorSaveBtn.dataset.initialized = 'true';
}
function bindMultiEditEvents() {
dom.applyMultiEditBtn.addEventListener('click', handleApplyMultiEdit);
const multiEditToggles = [
{ check: dom.multiEditEnableGroup, input: dom.multiEditGroupInput },
{ check: dom.multiEditEnableFavorite, input: dom.multiEditFavoriteSelect },
{ check: dom.multiEditEnableHidden, input: dom.multiEditHiddenSelect },
{ check: dom.multiEditEnableUserAgent, input: dom.multiEditUserAgentInput },
{ check: dom.multiEditEnableStreamHeaders, input: dom.multiEditStreamHeadersInput, extra: dom.multiEditStreamHeadersMode },
];
multiEditToggles.forEach(({check, input, extra}) => {
check.addEventListener('change', (e) => {
input.disabled = !e.target.checked;
if (extra) extra.disabled = !e.target.checked;
});
});
}
function updateGroupOrder() {
const currentGroups = [...new Set(editorChannels.filter(ch => ch).map(ch => ch['group-title'] || ''))];
const newGroupOrder = (groupOrder.length > 0 ? groupOrder : []).filter(group => currentGroups.includes(group));
currentGroups.forEach(group => { if (!newGroupOrder.includes(group)) newGroupOrder.push(group); });
groupOrder = newGroupOrder;
updateGroupFilter();
updateGroupSuggestions();
}
function renderTable() {
const fragment = document.createDocumentFragment();
dom.tableBody.innerHTML = '';
const searchTerm = dom.searchInput.value.toLowerCase().trim();
if (currentGroupFilter === '' && !searchTerm && !currentSort.column) {
const groupCounts = editorChannels.reduce((acc, channel) => {
if (!channel || channel.attributes?.hidden === 'true') return acc;
const groupKey = channel['group-title'] || '';
acc[groupKey] = (acc[groupKey] || 0) + 1;
return acc;
}, {});
groupOrder.forEach(groupKey => {
const count = groupCounts[groupKey] || 0;
if (count > 0) {
fragment.appendChild(createGroupHeaderRow(groupKey, count));
}
});
} else {
const filteredChannels = getFilteredAndSortedChannels();
if (currentGroupFilter) {
if (filteredChannels.length > 0) {
const groupKey = filteredChannels[0]['group-title'] || '';
fragment.appendChild(createGroupHeaderRow(groupKey, filteredChannels.length));
filteredChannels.forEach(channel => fragment.appendChild(createRow(channel)));
}
} else {
filteredChannels.forEach(channel => fragment.appendChild(createRow(channel)));
}
}
dom.tableBody.appendChild(fragment);
updateSortableForCurrentView();
updateSelectAllCheckboxState();
updateSortIcons();
}
function getFilteredAndSortedChannels() {
const searchTerm = dom.searchInput.value.toLowerCase().trim();
let channelsToProcess = editorChannels.filter(ch => {
if (!ch || ch.attributes?.hidden === 'true') {
return false;
}
if (currentGroupFilter && (ch['group-title'] || '') !== currentGroupFilter) {
return false;
}
if (searchTerm) {
if (!(
ch.name?.toLowerCase().includes(searchTerm) ||
ch.url?.toLowerCase().includes(searchTerm) ||
ch['group-title']?.toLowerCase().includes(searchTerm) ||
ch['tvg-id']?.toLowerCase().includes(searchTerm)
)) {
return false;
}
}
return true;
});
if (currentSort.column) {
channelsToProcess.sort((a, b) => {
let valA, valB;
switch (currentSort.column) {
case 'ch-number':
valA = parseInt(a.attributes?.['ch-number'], 10) || Infinity;
valB = parseInt(b.attributes?.['ch-number'], 10) || Infinity;
break;
default:
valA = (a[currentSort.column] || '').toLowerCase();
valB = (b[currentSort.column] || '').toLowerCase();
break;
}
let comparison = valA < valB ? -1 : (valA > valB ? 1 : 0);
return comparison * (currentSort.direction === 'asc' ? 1 : -1);
});
}
return channelsToProcess;
}
function createRow(channel) {
const row = document.createElement('tr');
row.dataset.editorId = channel.editorId;
row.dataset.groupParent = channel['group-title'] || '';
row.className = `channel-row ${channel.editorId === selectedChannelId ? 'selected-row' : ''}`;
const logoHtml = channel['tvg-logo'] ? `` : `-`;
const nameHtml = `${channel.favorite ? '' : ''}${escapeHtml(channel.name || '')}`;
row.innerHTML = `