Skip to main content

max / makenotwork

4.5 KB · 115 lines History Blame Raw
1 (function() {
2 var __cfg = document.getElementById('partial-item-text-editor-cfg');
3 var ITEM_ID = __cfg ? __cfg.dataset.itemId : '';
4
5 function switchEditorTab(tab) {
6 document.querySelectorAll('.editor-tab').forEach(t => t.classList.remove('is-selected'));
7 document.querySelector('.editor-tab[data-tab="' + tab + '"]').classList.add('is-selected');
8
9 document.querySelectorAll('.editor-panel').forEach(p => p.classList.remove('active'));
10 document.getElementById(tab + '-panel').classList.add('active');
11
12 if (tab === 'preview') {
13 renderMarkdownPreview();
14 }
15 }
16
17 function renderMarkdownPreview() {
18 const body = document.getElementById('text-body').value;
19 const preview = document.getElementById('markdown-preview');
20
21 // Basic markdown rendering (paragraphs, bold, italic, headers)
22 let html = body
23 .split('\n\n').map(p => p.trim()).filter(p => p).map(p => {
24 // Headers
25 if (p.startsWith('### ')) return '<h3>' + escapeHtml(p.slice(4)) + '</h3>';
26 if (p.startsWith('## ')) return '<h2>' + escapeHtml(p.slice(3)) + '</h2>';
27 if (p.startsWith('# ')) return '<h1>' + escapeHtml(p.slice(2)) + '</h1>';
28 // Paragraph with inline formatting
29 let text = escapeHtml(p);
30 text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
31 text = text.replace(/\*(.+?)\*/g, '<em>$1</em>');
32 text = text.replace(/`(.+?)`/g, '<code>$1</code>');
33 return '<p>' + text + '</p>';
34 }).join('\n');
35
36 preview.innerHTML = html || '<p class="text-editor-placeholder">Nothing to preview...</p>';
37 }
38
39
40 function updateWordCount() {
41 const body = document.getElementById('text-body').value;
42 const words = body.trim().split(/\s+/).filter(w => w).length;
43 const readingTime = Math.max(1, Math.ceil(words / 200));
44 document.getElementById('word-count').textContent = words + ' words';
45 document.querySelector('.reading-time').textContent = readingTime + ' min read';
46 }
47
48 function saveTextContent() {
49 const body = document.getElementById('text-body').value;
50 const btn = document.getElementById('save-text-btn');
51 const status = document.getElementById('text-save-status');
52 const itemId = ITEM_ID;
53
54 btn.disabled = true;
55 status.innerHTML = '';
56
57 fetch('/api/items/' + itemId + '/text', {
58 method: 'PUT',
59 headers: { 'Content-Type': 'application/json', ...csrfHeaders() },
60 body: JSON.stringify({ body: body })
61 })
62 .then(res => res.json())
63 .then(data => {
64 status.innerHTML = '<span class="save-status success">Saved</span>';
65 if (data.word_count !== undefined) {
66 document.getElementById('word-count').textContent = data.word_count + ' words';
67 }
68 })
69 .catch(err => {
70 status.innerHTML = '<span class="save-status error">Error saving</span>';
71 })
72 .finally(() => {
73 btn.disabled = false;
74 });
75 }
76
77 document.getElementById('text-body').addEventListener('input', updateWordCount);
78
79 // Auto-save: debounce text body changes (30s after last keystroke)
80 var autoSaveTimer = null;
81 var autoSaveStatus = document.getElementById('text-save-status');
82
83 document.getElementById('text-body').addEventListener('input', function() {
84 clearTimeout(autoSaveTimer);
85 autoSaveTimer = setTimeout(function() {
86 autoSaveStatus.innerHTML = '<span class="save-status saving">Saving...</span>';
87 var body = document.getElementById('text-body').value;
88 fetch('/api/items/' + ITEM_ID + '/text', {
89 method: 'PUT',
90 headers: { 'Content-Type': 'application/json', ...csrfHeaders() },
91 body: JSON.stringify({ body: body })
92 })
93 .then(function(res) { return res.json(); })
94 .then(function(data) {
95 autoSaveStatus.innerHTML = '<span class="save-status success">Auto-saved</span>';
96 if (data.word_count !== undefined) {
97 document.getElementById('word-count').textContent = data.word_count + ' words';
98 }
99 setTimeout(function() {
100 if (autoSaveStatus.textContent === 'Auto-saved') autoSaveStatus.innerHTML = '';
101 }, 3000);
102 })
103 .catch(function() {
104 autoSaveStatus.innerHTML = '<span class="save-status error">Auto-save failed</span>';
105 });
106 }, 30000);
107 });
108
109 window.switchEditorTab = switchEditorTab;
110 window.renderMarkdownPreview = renderMarkdownPreview;
111 window.escapeHtml = escapeHtml;
112 window.updateWordCount = updateWordCount;
113 window.saveTextContent = saveTextContent;
114 })();
115