// Project sections (Pages) editor — markdown content blocks for a project.
// Mirrors item sections but scoped to projects. Loaded by the Settings tab.
(function() {
'use strict';
function csrfHeaders() {
var token = document.querySelector('meta[name="csrf-token"]');
return token ? { 'X-CSRF-Token': token.content } : {};
}
function escapeHtml(s) {
var d = document.createElement('div');
d.textContent = s;
return d.innerHTML;
}
function showToast(msg) {
if (window.showToast) { window.showToast(msg); return; }
alert(msg);
}
function bodyFor(id) {
var el = document.querySelector('textarea[data-body-for="' + id + '"]');
return el ? el.value : '';
}
function updateCount(delta) {
var el = document.getElementById('psection-count');
if (el) el.textContent = parseInt(el.textContent || '0') + delta;
}
function attachRowHandlers(row) {
var delBtn = row.querySelector('.psection-del-btn');
var editBtn = row.querySelector('.psection-edit-btn');
delBtn.addEventListener('click', function() {
var id = this.dataset.id;
if (!confirm('Delete this page?')) return;
fetch('/api/project-sections/' + id, { method: 'DELETE', headers: csrfHeaders() })
.then(function(res) {
if (res.ok) {
var hidden = document.querySelector('textarea[data-body-for="' + id + '"]');
if (hidden) hidden.remove();
row.remove();
updateCount(-1);
} else {
apiErrorMessage(res, 'Failed to delete').then(function(m) { showToast(m); });
}
})
.catch(function() { showToast('Failed to delete'); });
});
editBtn.addEventListener('click', function() {
var id = this.dataset.id;
var title = this.dataset.title || row.querySelector('span').textContent;
document.getElementById('edit-psec-id').value = id;
document.getElementById('edit-psec-title').value = title;
document.getElementById('edit-psec-body').value = bodyFor(id);
document.getElementById('psec-edit-status').textContent = '';
document.getElementById('psection-edit-modal').classList.remove('hidden');
});
}
function init() {
var addBtn = document.getElementById('add-psec-btn');
if (!addBtn) return;
var projectId = addBtn.dataset.projectId;
addBtn.addEventListener('click', function() {
var title = document.getElementById('new-psec-title').value.trim();
var body = document.getElementById('new-psec-body').value;
var status = document.getElementById('psec-add-status');
if (!title) { status.textContent = 'Title is required'; return; }
this.disabled = true;
status.textContent = '';
fetch('/api/projects/' + projectId + '/sections', {
method: 'POST',
headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
body: JSON.stringify({ title: title, body: body })
})
.then(function(res) {
if (!res.ok) return res.json().then(function(d) { throw new Error(d.error || 'Failed'); });
return res.json();
})
.then(function(sec) {
var empty = document.getElementById('psections-empty');
if (empty) empty.remove();
var list = document.getElementById('psections-list');
var row = document.createElement('div');
row.className = 'psection-row';
row.dataset.id = sec.id;
row.innerHTML =
'' + escapeHtml(sec.title) + '' +
'#section-' + escapeHtml(sec.slug) + '' +
'' + (sec.body || '').length + ' chars' +
'' +
'';
list.appendChild(row);
var hidden = document.createElement('textarea');
hidden.className = 'hidden';
hidden.dataset.bodyFor = sec.id;
hidden.value = sec.body || '';
list.appendChild(hidden);
attachRowHandlers(row);
updateCount(1);
document.getElementById('new-psec-title').value = '';
document.getElementById('new-psec-body').value = '';
document.getElementById('psection-add-details').removeAttribute('open');
})
.catch(function(err) { status.textContent = err.message; })
.finally(function() { addBtn.disabled = false; });
});
document.getElementById('save-psec-btn').addEventListener('click', function() {
var id = document.getElementById('edit-psec-id').value;
var title = document.getElementById('edit-psec-title').value.trim();
var body = document.getElementById('edit-psec-body').value;
var status = document.getElementById('psec-edit-status');
if (!title) { status.textContent = 'Title is required'; return; }
this.disabled = true;
fetch('/api/project-sections/' + id, {
method: 'PUT',
headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
body: JSON.stringify({ title: title, body: body })
})
.then(function(res) {
if (!res.ok) return res.json().then(function(d) { throw new Error(d.error || 'Failed'); });
return res.json();
})
.then(function(sec) {
var row = document.querySelector('.psection-row[data-id="' + id + '"]');
if (row) {
row.querySelector('.psection-row-title').textContent = sec.title;
row.querySelector('.psection-row-anchor').textContent = '#section-' + sec.slug;
row.querySelector('.psection-row-length').textContent = (sec.body || '').length + ' chars';
row.querySelector('.psection-edit-btn').dataset.title = sec.title;
}
var hidden = document.querySelector('textarea[data-body-for="' + id + '"]');
if (hidden) hidden.value = sec.body || '';
document.getElementById('psection-edit-modal').classList.add('hidden');
})
.catch(function(err) { status.textContent = err.message; })
.finally(function() { document.getElementById('save-psec-btn').disabled = false; });
});
document.getElementById('cancel-psec-btn').addEventListener('click', function() {
document.getElementById('psection-edit-modal').classList.add('hidden');
});
document.querySelectorAll('.psection-row').forEach(attachRowHandlers);
}
// HTMX swaps in the settings partial; bind on swap + on initial load.
if (document.getElementById('add-psec-btn')) init();
document.body.addEventListener('htmx:afterSettle', function(e) {
if (e.target && e.target.querySelector && e.target.querySelector('#add-psec-btn')) init();
});
})();