Skip to main content

max / makenotwork

3.4 KB · 82 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 // The Write/Preview pair, the preview pane and the markdown rendering behind
6 // them are the described field's now (crate::quasi::rich_field, bound by
7 // markdown-editor.js). What used to be here was a regex over h1-h3, bold,
8 // italic and inline code, which is not what publishing does; the pane is
9 // filled from /api/preview/markdown instead. What stays is this screen's own:
10 // the word count, the explicit save, and the autosave clock.
11
12 function updateWordCount() {
13 const body = document.getElementById('text-body').value;
14 const words = body.trim().split(/\s+/).filter(w => w).length;
15 const readingTime = Math.max(1, Math.ceil(words / 200));
16 document.getElementById('word-count').textContent = words + ' words';
17 document.querySelector('.reading-time').textContent = readingTime + ' min read';
18 }
19
20 function saveTextContent() {
21 const body = document.getElementById('text-body').value;
22 const btn = document.getElementById('save-text-btn');
23 const status = document.getElementById('text-save-status');
24 const itemId = ITEM_ID;
25
26 btn.disabled = true;
27 status.innerHTML = '';
28
29 fetch('/api/items/' + itemId + '/text', {
30 method: 'PUT',
31 headers: { 'Content-Type': 'application/json', ...csrfHeaders() },
32 body: JSON.stringify({ body: body })
33 })
34 .then(res => res.json())
35 .then(data => {
36 status.innerHTML = '<span class="save-status success">Saved</span>';
37 if (data.word_count !== undefined) {
38 document.getElementById('word-count').textContent = data.word_count + ' words';
39 }
40 })
41 .catch(err => {
42 status.innerHTML = '<span class="save-status error">Error saving</span>';
43 })
44 .finally(() => {
45 btn.disabled = false;
46 });
47 }
48
49 document.getElementById('text-body').addEventListener('input', updateWordCount);
50
51 // Auto-save: debounce text body changes (30s after last keystroke)
52 var autoSaveStatus = document.getElementById('text-save-status');
53
54 document.getElementById('text-body').addEventListener('input', function() {
55 // Thirty seconds is a save cadence rather than a wait for the typing to
56 // stop, and `makeover-timing` names no such intent, so the number stays
57 // here. The closure that spent it does not.
58 window.timing.debounce('text-autosave', function() {
59 autoSaveStatus.innerHTML = '<span class="save-status saving">Saving...</span>';
60 var body = document.getElementById('text-body').value;
61 fetch('/api/items/' + ITEM_ID + '/text', {
62 method: 'PUT',
63 headers: { 'Content-Type': 'application/json', ...csrfHeaders() },
64 body: JSON.stringify({ body: body })
65 })
66 .then(function(res) { return res.json(); })
67 .then(function(data) {
68 autoSaveStatus.innerHTML = '<span class="save-status success">Auto-saved</span>';
69 if (data.word_count !== undefined) {
70 document.getElementById('word-count').textContent = data.word_count + ' words';
71 }
72 window.timing.clearStatusLater(autoSaveStatus, 'Auto-saved');
73 })
74 .catch(function() {
75 autoSaveStatus.innerHTML = '<span class="save-status error">Auto-save failed</span>';
76 });
77 }, 30000);
78 });
79
80 window.saveTextContent = saveTextContent;
81 })();
82