annotate mrjunejune/src/notes/editor.js @ 202:b9b184b3303c

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