annotate mrjunejune/src/notes/editor.js @ 201:6cdee35a7ba9

[MrJuneJune] notes
author MrJuneJune <me@mrjunejune.com>
date Sun, 15 Feb 2026 07:07:50 -0800
parents
children b9b184b3303c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
201
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 console.log("june");
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 let editor = null;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4 let currentNoteId = 'index';
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 function getAuthToken() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7 return localStorage.getItem('notes-auth-token');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 function requireAuth() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 if (!getAuthToken()) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 const returnUrl = encodeURIComponent(window.location.pathname);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 window.location.href = '/notes/login?return=' + returnUrl;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 return false;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 return true;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19 function logout() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 localStorage.removeItem('notes-auth-token');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 window.location.href = '/notes/login';
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 function getNoteIdFromPath() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 const path = window.location.pathname;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 const match = path.match(/^\/notes\/(.+)$/);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 if (match && match[1] && match[1] !== 'login') {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 return decodeURIComponent(match[1]);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 return 'index';
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 function showNewNoteDialog() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 document.getElementById('new-note-dialog').classList.add('show');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 document.getElementById('new-note-id').focus();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 function hideNewNoteDialog() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 document.getElementById('new-note-dialog').classList.remove('show');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 document.getElementById('new-note-id').value = '';
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 function createNewNote() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 let noteId = document.getElementById('new-note-id').value.trim();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 if (!noteId) return;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 // Sanitize note ID
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 noteId = noteId.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 hideNewNoteDialog();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 window.location.href = '/notes/' + encodeURIComponent(noteId);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 // Handle Enter key in new note dialog
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 document.getElementById('new-note-id').addEventListener('keydown', function(e) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 if (e.key === 'Enter') {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 e.preventDefault();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 createNewNote();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 if (e.key === 'Escape') {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 hideNewNoteDialog();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 // Close dialog on backdrop click
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66 document.getElementById('new-note-dialog').addEventListener('click', function(e) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 if (e.target === this) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 hideNewNoteDialog();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 async function uploadFile(file) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73 const token = getAuthToken();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 if (!token) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75 throw new Error('Not authenticated');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
76 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
77
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 // 1. Create media record
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 const createResp = await fetch('/api/media/create', {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80 method: 'POST',
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
81 headers: {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
82 'Authorization': 'Bearer ' + token,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
83 'Content-Type': 'application/json'
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
84 },
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
85 body: JSON.stringify({
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
86 filename: file.name,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
87 content_type: file.type
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
88 })
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
89 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
90
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
91 if (!createResp.ok) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
92 const error = await createResp.json();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
93 throw new Error(error.error || 'Failed to create media record');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
94 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
95
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
96 const { media_id, upload_url } = await createResp.json();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
97
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
98 // 2. Upload to S3
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
99 const uploadResp = await fetch(upload_url, {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
100 method: 'PUT',
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
101 headers: { 'Content-Type': file.type },
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
102 body: file
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
103 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
104
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
105 if (!uploadResp.ok) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
106 throw new Error('S3 upload failed');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
107 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
108
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
109 // 3. Mark uploaded
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
110 await fetch(`/api/media/${media_id}/uploaded`, {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
111 method: 'POST',
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
112 headers: { 'Authorization': 'Bearer ' + token }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
113 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
114
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
115 // 4. Poll for images, immediate return for non-images
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
116 if (file.type.startsWith('image/')) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
117 return await pollForProcessedImage(media_id);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
118 } else {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
119 // For non-images, return the original S3 URL
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
120 const s3_url = upload_url.split('?')[0];
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
121 return { url: s3_url };
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
122 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
123 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
124
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
125 async function pollForProcessedImage(mediaId) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
126 const token = getAuthToken();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
127 const maxAttempts = 60; // 2 minutes max
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
128
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
129 for (let i = 0; i < maxAttempts; i++) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
130 await new Promise(r => setTimeout(r, 2000)); // 2 sec interval
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
131
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
132 const resp = await fetch(`/api/media/${mediaId}/status`, {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
133 headers: { 'Authorization': 'Bearer ' + token }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
134 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
135
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
136 if (!resp.ok) continue;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
137
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
138 const { status, processed_url, error_message } = await resp.json();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
139
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
140 if (status === 'finished') return { url: processed_url };
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
141 if (status === 'error') throw new Error(error_message || 'Processing failed');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
142 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
143
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
144 throw new Error('Processing timeout');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
145 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
146
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
147 async function saveContent(content) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
148 const token = getAuthToken();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
149 if (!token) return;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
150
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
151 const response = await fetch('/api/editor/save', {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
152 method: 'POST',
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
153 headers: {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
154 'Authorization': 'Bearer ' + token,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
155 'Content-Type': 'application/json'
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
156 },
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
157 body: JSON.stringify({
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
158 doc_id: currentNoteId,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
159 content: content
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
160 })
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
161 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
162
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
163 if (!response.ok) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
164 throw new Error('Failed to save');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
165 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
166 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
167
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
168 async function loadNote(noteId) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
169 const token = getAuthToken();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
170 if (!token) return;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
171
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
172 try {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
173 const response = await fetch('/api/editor/load/' + encodeURIComponent(noteId), {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
174 headers: { 'Authorization': 'Bearer ' + token }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
175 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
176
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
177 if (response.ok) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
178 const data = await response.json();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
179 editor.setContent(data.content || '');
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
180 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
181 } catch (error) {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
182 console.error('Failed to load note:', error);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
183 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
184 }
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
185
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
186 // Initialize
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
187 document.addEventListener('DOMContentLoaded', function() {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
188 if (!requireAuth()) return;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
189
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
190 currentNoteId = getNoteIdFromPath();
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
191 document.getElementById('note-id-display').textContent = currentNoteId;
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
192
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
193 // Update page title
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
194 document.title = currentNoteId + ' | Notes';
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
195
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
196 editor = RichEditor.init('editor-container', {
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
197 uploadCallback: uploadFile,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
198 saveCallback: saveContent,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
199 debounceMs: 1500,
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
200 placeholder: 'Start writing... (paste images, drag files, or use /upload)\n\nTip: Click "+ New Note" to create linked notes.'
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
201 });
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
202
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
203 loadNote(currentNoteId);
6cdee35a7ba9 [MrJuneJune] notes
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
204 });