(function() { var __cfg = document.getElementById('tab-project-content-cfg'); var PROJECT_SLUG = __cfg ? __cfg.dataset.projectSlug : ''; function toggleSelectAll(checked) { var boxes = document.querySelectorAll('.bulk-check'); for (var i = 0; i < boxes.length; i++) boxes[i].checked = checked; var selectAll = document.getElementById('select-all'); if (selectAll) selectAll.checked = checked; updateBulkUI(); } function updateBulkUI() { var checked = document.querySelectorAll('.bulk-check:checked'); var bar = document.getElementById('bulk-action-bar'); var countEl = document.getElementById('bulk-count'); var selectAll = document.getElementById('select-all'); var allBoxes = document.querySelectorAll('.bulk-check'); if (!bar) return; var hasSelection = checked.length > 0; bar.classList.toggle('bulk-action-bar--active', hasSelection); bar.dataset.active = hasSelection ? 'true' : 'false'; countEl.textContent = checked.length + ' selected'; var buttons = bar.querySelectorAll('button'); for (var i = 0; i < buttons.length; i++) buttons[i].disabled = !hasSelection; if (selectAll) selectAll.checked = allBoxes.length > 0 && checked.length === allBoxes.length; if (!hasSelection) { document.getElementById('bulk-price-form').classList.add('hidden'); document.getElementById('bulk-tag-form').classList.add('hidden'); } } function bulkAction(action) { var checked = document.querySelectorAll('.bulk-check:checked'); if (checked.length === 0) return; var titles = []; for (var i = 0; i < checked.length; i++) { var row = checked[i].closest('tr'); var link = row ? row.querySelector('td:nth-child(3) a') : null; if (link) titles.push(link.textContent.trim()); } if (action === 'delete') { var msg = 'Delete ' + checked.length + ' item(s)? This cannot be undone.\n\n' + titles.join('\n'); if (!confirm(msg)) return; } var count = checked.length; var params = new URLSearchParams(); for (var i = 0; i < checked.length; i++) { params.append('item_ids', checked[i].value); } fetch('/api/items/bulk/' + action, { method: 'POST', headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()), body: params.toString() }) .then(function(r) { if (!r.ok) return r.text().then(function(t) { var msg = 'Bulk ' + action + ' failed (' + r.status + ')'; try { var parsed = JSON.parse(t); if (parsed.error) msg = parsed.error; } catch (_) {} throw new Error(msg); }); var label = action === 'delete' ? 'deleted' : action === 'publish' ? 'published' : 'unpublished'; showToast(count + ' item(s) ' + label + '.', 'success'); htmx.ajax('GET', '/dashboard/project/' + PROJECT_SLUG + '/tabs/content', '#tab-content'); }) .catch(function(err) { showToast(err.message || 'Bulk operation failed'); }); } function quickPublish(itemId) { var params = new URLSearchParams(); params.append('item_ids', itemId); fetch('/api/items/bulk/publish', { method: 'POST', headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()), body: params.toString() }).then(function(r) { if (!r.ok) return r.text().then(function(t) { var msg = 'Publish failed'; try { var parsed = JSON.parse(t); if (parsed.error) msg = parsed.error; } catch (_) {} throw new Error(msg); }); showToast('Item published.', 'success'); htmx.ajax('GET', '/dashboard/project/' + PROJECT_SLUG + '/tabs/content', '#tab-content'); }).catch(function(err) { showToast(err.message || 'Publish failed'); }); } function showBulkPrice() { document.getElementById('bulk-price-form').classList.remove('hidden'); document.getElementById('bulk-tag-form').classList.add('hidden'); document.getElementById('bulk-price-input').focus(); } function showBulkTag() { document.getElementById('bulk-tag-form').classList.remove('hidden'); document.getElementById('bulk-price-form').classList.add('hidden'); document.getElementById('bulk-tag-input').focus(); } function submitBulkPrice() { var checked = document.querySelectorAll('.bulk-check:checked'); if (checked.length === 0) return; var price = document.getElementById('bulk-price-input').value; if (price === '') { showToast('Enter a price'); return; } var params = new URLSearchParams(); for (var i = 0; i < checked.length; i++) params.append('item_ids', checked[i].value); params.append('price_dollars', price); fetch('/api/items/bulk/price', { method: 'POST', headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()), body: params.toString() }) .then(function(r) { if (!r.ok) return r.text().then(function(t) { var msg = 'Could not update prices. Try again, or refresh the page.'; try { var p = JSON.parse(t); if (p.error) msg = p.error; } catch (_) {} throw new Error(msg); }); document.getElementById('bulk-price-form').classList.add('hidden'); htmx.ajax('GET', '/dashboard/project/' + PROJECT_SLUG + '/tabs/content', '#tab-content'); }) .catch(function(err) { showToast(err.message || 'Could not update prices. Try again, or refresh the page.'); }); } function submitBulkTag() { var checked = document.querySelectorAll('.bulk-check:checked'); if (checked.length === 0) return; var tag = document.getElementById('bulk-tag-input').value.trim(); if (!tag) { showToast('Enter a tag.'); return; } var params = new URLSearchParams(); for (var i = 0; i < checked.length; i++) params.append('item_ids', checked[i].value); params.append('tag_slug', tag); fetch('/api/items/bulk/tag', { method: 'POST', headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()), body: params.toString() }) .then(function(r) { if (!r.ok) return r.text().then(function(t) { var msg = 'Could not add the tag. Try again, or refresh the page.'; try { var p = JSON.parse(t); if (p.error) msg = p.error; } catch (_) {} throw new Error(msg); }); document.getElementById('bulk-tag-form').classList.add('hidden'); document.getElementById('bulk-tag-input').value = ''; htmx.ajax('GET', '/dashboard/project/' + PROJECT_SLUG + '/tabs/content', '#tab-content'); }) .catch(function(err) { showToast(err.message || 'Could not add the tag. Try again, or refresh the page.'); }); } function toggleBundleChildren(bundleId) { var rows = document.querySelectorAll('.bundle-child-' + bundleId); var btn = document.querySelector('tr:has(.bulk-check[value="' + bundleId + '"]) .bundle-toggle'); var visible = rows.length > 0 && !rows[0].classList.contains('hidden'); for (var i = 0; i < rows.length; i++) { rows[i].classList.toggle('hidden', visible); } if (btn) btn.innerHTML = visible ? '▶' : '▼'; } function filterContentTable() { var query = (document.getElementById('content-search').value || '').toLowerCase(); var status = document.getElementById('content-filter-status').value; var type = document.getElementById('content-filter-type').value; var rows = document.querySelectorAll('.data-table tbody > tr:not(.bundle-child)'); for (var i = 0; i < rows.length; i++) { var row = rows[i]; var title = (row.querySelector('td:nth-child(3)') || {}).textContent || ''; var rowType = (row.querySelector('td:nth-child(4)') || {}).textContent || ''; var rowStatus = row.querySelector('.badge') ? row.querySelector('.badge').textContent.trim() : ''; var matchQuery = !query || title.toLowerCase().indexOf(query) !== -1; var matchStatus = !status || rowStatus === status; var matchType = !type || rowType.trim().indexOf(type) !== -1; var visible = matchQuery && matchStatus && matchType; row.classList.toggle('hidden', !visible); var itemCheckbox = row.querySelector('.bulk-check'); if (itemCheckbox && !visible) { var children = document.querySelectorAll('.bundle-child-' + itemCheckbox.value); for (var j = 0; j < children.length; j++) { children[j].classList.add('hidden'); } } } } (function() { var seen = {}; var opts = document.querySelectorAll('.content-type-opt'); for (var i = 0; i < opts.length; i++) { if (seen[opts[i].value]) { opts[i].remove(); } else { seen[opts[i].value] = true; } } })(); var contentSortState = { col: -1, asc: true }; function sortContentTable(colIndex, sortType) { var table = document.querySelector('.data-table'); if (!table) return; var tbody = table.querySelector('tbody'); var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr:not(.bundle-child)')); if (contentSortState.col === colIndex) { contentSortState.asc = !contentSortState.asc; } else { contentSortState.col = colIndex; contentSortState.asc = true; } function getValue(row) { var cell = row.cells[colIndex]; if (!cell) return ''; var text = cell.textContent.trim(); if (sortType === 'num') { return parseInt(text.replace(/[^0-9-]/g, ''), 10) || 0; } if (sortType === 'money') { if (text.toLowerCase() === 'free') return 0; return parseFloat(text.replace(/[^0-9.-]/g, '')) || 0; } return text.toLowerCase(); } rows.sort(function(a, b) { var va = getValue(a); var vb = getValue(b); var cmp = 0; if (typeof va === 'number') { cmp = va - vb; } else { cmp = va < vb ? -1 : va > vb ? 1 : 0; } return contentSortState.asc ? cmp : -cmp; }); for (var i = 0; i < rows.length; i++) { tbody.appendChild(rows[i]); var checkbox = rows[i].querySelector('.bulk-check'); if (checkbox) { var children = Array.prototype.slice.call(tbody.querySelectorAll('.bundle-child-' + checkbox.value)); for (var j = 0; j < children.length; j++) { tbody.appendChild(children[j]); } } } var arrows = document.querySelectorAll('.sort-arrow'); for (var i = 0; i < arrows.length; i++) { var col = parseInt(arrows[i].dataset.col, 10); if (col === colIndex) { arrows[i].textContent = contentSortState.asc ? '▲' : '▼'; arrows[i].classList.add('sort-arrow--active'); } else { arrows[i].textContent = ''; arrows[i].classList.remove('sort-arrow--active'); } } } function inlineRename(itemId) { var container = document.getElementById('item-title-' + itemId); var link = container.querySelector('a'); var currentTitle = link.textContent; var href = link.getAttribute('href'); var input = document.createElement('input'); input.type = 'text'; input.value = currentTitle; input.className = 'inline-rename-input'; function restore(newTitle) { container.innerHTML = ''; var a = document.createElement('a'); a.href = href; a.className = 'fw-bold'; a.textContent = newTitle; container.appendChild(a); } function save() { var newTitle = input.value.trim(); if (!newTitle || newTitle === currentTitle) { restore(currentTitle); return; } var form = new FormData(); form.append('title', newTitle); fetch('/api/items/' + itemId, { method: 'PUT', headers: csrfHeaders(), body: form }) .then(function(r) { if (!r.ok) throw new Error('Failed'); return r.json(); }) .then(function(data) { restore(data.title); }) .catch(function() { restore(currentTitle); }); } input.addEventListener('keydown', function(e) { if (e.key === 'Enter') { e.preventDefault(); save(); } if (e.key === 'Escape') { restore(currentTitle); } }); input.addEventListener('blur', save); container.innerHTML = ''; container.appendChild(input); input.focus(); input.select(); } window.toggleSelectAll = toggleSelectAll; window.updateBulkUI = updateBulkUI; window.bulkAction = bulkAction; window.quickPublish = quickPublish; window.showBulkPrice = showBulkPrice; window.showBulkTag = showBulkTag; window.submitBulkPrice = submitBulkPrice; window.submitBulkTag = submitBulkTag; window.toggleBundleChildren = toggleBundleChildren; window.filterContentTable = filterContentTable; window.sortContentTable = sortContentTable; window.inlineRename = inlineRename; })();