(function() { var __cfg = document.getElementById('partial-item-text-editor-cfg'); var ITEM_ID = __cfg ? __cfg.dataset.itemId : ''; // The Write/Preview pair, the preview pane and the markdown rendering behind // them are the described field's now (crate::quasi::rich_field, bound by // markdown-editor.js). What used to be here was a regex over h1-h3, bold, // italic and inline code, which is not what publishing does; the pane is // filled from /api/preview/markdown instead. What stays is this screen's own: // the word count, the explicit save, and the autosave clock. function updateWordCount() { const body = document.getElementById('text-body').value; const words = body.trim().split(/\s+/).filter(w => w).length; const readingTime = Math.max(1, Math.ceil(words / 200)); document.getElementById('word-count').textContent = words + ' words'; document.querySelector('.reading-time').textContent = readingTime + ' min read'; } function saveTextContent() { const body = document.getElementById('text-body').value; const btn = document.getElementById('save-text-btn'); const status = document.getElementById('text-save-status'); const itemId = ITEM_ID; btn.disabled = true; status.innerHTML = ''; fetch('/api/items/' + itemId + '/text', { method: 'PUT', headers: { 'Content-Type': 'application/json', ...csrfHeaders() }, body: JSON.stringify({ body: body }) }) .then(res => res.json()) .then(data => { status.innerHTML = 'Saved'; if (data.word_count !== undefined) { document.getElementById('word-count').textContent = data.word_count + ' words'; } }) .catch(err => { status.innerHTML = 'Error saving'; }) .finally(() => { btn.disabled = false; }); } document.getElementById('text-body').addEventListener('input', updateWordCount); // Auto-save: debounce text body changes (30s after last keystroke) var autoSaveTimer = null; var autoSaveStatus = document.getElementById('text-save-status'); document.getElementById('text-body').addEventListener('input', function() { clearTimeout(autoSaveTimer); autoSaveTimer = setTimeout(function() { autoSaveStatus.innerHTML = 'Saving...'; var body = document.getElementById('text-body').value; fetch('/api/items/' + ITEM_ID + '/text', { method: 'PUT', headers: { 'Content-Type': 'application/json', ...csrfHeaders() }, body: JSON.stringify({ body: body }) }) .then(function(res) { return res.json(); }) .then(function(data) { autoSaveStatus.innerHTML = 'Auto-saved'; if (data.word_count !== undefined) { document.getElementById('word-count').textContent = data.word_count + ' words'; } setTimeout(function() { if (autoSaveStatus.textContent === 'Auto-saved') autoSaveStatus.innerHTML = ''; }, 3000); }) .catch(function() { autoSaveStatus.innerHTML = 'Auto-save failed'; }); }, 30000); }); window.saveTextContent = saveTextContent; })();