11import OverType from 'overtype' ;
22import { MarkdownParser } from 'overtype/parser' ;
33import { isDarkMode } from '../../js/theme.ts' ;
4- import { downloadFile } from '../../js/file-utils.ts' ;
5- import { htmlToPdfBuffer } from '../../js/mupdf-utils.ts' ;
64import { showMessage } from '../../js/ui.ts' ;
7-
8- interface Note {
9- id ?: number ;
10- content : string ;
11- createdAt : number ;
12- updatedAt ?: number ;
13- }
14-
15- const DB_NAME = 'NotesDB' ;
16- const STORE_NAME = 'notes' ;
17- const DB_VERSION = 1 ;
18-
19- function openDB ( ) : Promise < IDBDatabase > {
20- return new Promise ( ( resolve , reject ) => {
21- const request = indexedDB . open ( DB_NAME , DB_VERSION ) ;
22- request . onerror = ( ) => reject ( request . error ) ;
23- request . onsuccess = ( ) => resolve ( request . result ) ;
24- request . onupgradeneeded = ( event ) => {
25- const db = ( event . target as IDBOpenDBRequest ) . result ;
26- if ( ! db . objectStoreNames . contains ( STORE_NAME ) ) {
27- db . createObjectStore ( STORE_NAME , { keyPath : 'id' , autoIncrement : true } ) ;
28- }
29- } ;
30- } ) ;
31- }
5+ import { openDB , getAllNotes , saveNote , deleteNote , getNoteById } from './db.ts' ;
6+ import { removeMarkdownSyntax , exportNoteToPdf } from './pdf-utils.ts' ;
7+ import type { Note } from './types.ts' ;
328
339// noinspection JSUnusedGlobalSymbols
3410export default async function init ( ) {
@@ -48,12 +24,8 @@ export default async function init() {
4824 let editingId : number | null = null ;
4925
5026 async function loadNotes ( query = '' ) {
51- const transaction = db . transaction ( STORE_NAME , 'readonly' ) ;
52- const store = transaction . objectStore ( STORE_NAME ) ;
53- const request = store . getAll ( ) ;
54-
55- request . onsuccess = ( ) => {
56- let notes : Note [ ] = request . result ;
27+ try {
28+ let notes = await getAllNotes ( db ) ;
5729
5830 if ( query ) {
5931 const q = query . toLowerCase ( ) ;
@@ -62,7 +34,10 @@ export default async function init() {
6234
6335 notes . sort ( ( a , b ) => ( b . updatedAt || b . createdAt ) - ( a . updatedAt || a . createdAt ) ) ;
6436 renderNotes ( notes ) ;
65- } ;
37+ } catch ( e ) {
38+ console . error ( 'Failed to load notes:' , e ) ;
39+ showMessage ( 'Failed to load notes.' , { type : 'alert' } ) ;
40+ }
6641 }
6742
6843 function renderNotes ( notes : Note [ ] ) {
@@ -117,33 +92,18 @@ export default async function init() {
11792 . join ( '' ) ;
11893 }
11994
120- async function saveNote ( ) {
95+ async function handleSave ( ) {
12196 const content = overType . getValue ( ) . trim ( ) ;
12297 if ( ! content ) return ;
12398
124- const transaction = db . transaction ( STORE_NAME , 'readwrite' ) ;
125- const store = transaction . objectStore ( STORE_NAME ) ;
126-
127- if ( editingId !== null ) {
128- const request = store . get ( editingId ) ;
129- request . onsuccess = ( ) => {
130- const note = request . result ;
131- note . content = content ;
132- note . updatedAt = Date . now ( ) ;
133- store . put ( note ) ;
134- } ;
135- } else {
136- const note : Note = {
137- content,
138- createdAt : Date . now ( ) ,
139- } ;
140- store . add ( note ) ;
141- }
142-
143- transaction . oncomplete = ( ) => {
99+ try {
100+ await saveNote ( db , content , editingId ) ;
144101 resetForm ( ) ;
145102 loadNotes ( searchInput . value ) ;
146- } ;
103+ } catch ( e ) {
104+ console . error ( 'Failed to save note:' , e ) ;
105+ showMessage ( 'Failed to save note.' , { type : 'alert' } ) ;
106+ }
147107 }
148108
149109 function resetForm ( ) {
@@ -155,12 +115,8 @@ export default async function init() {
155115 }
156116
157117 async function startEdit ( id : number ) {
158- const transaction = db . transaction ( STORE_NAME , 'readonly' ) ;
159- const store = transaction . objectStore ( STORE_NAME ) ;
160- const request = store . get ( id ) ;
161-
162- request . onsuccess = ( ) => {
163- const note = request . result ;
118+ try {
119+ const note = await getNoteById ( db , id ) ;
164120 if ( note ) {
165121 editingId = id ;
166122 overType . setValue ( note . content ) ;
@@ -170,71 +126,36 @@ export default async function init() {
170126 overType . focus ( ) ;
171127 window . scrollTo ( { top : 0 , behavior : 'smooth' } ) ;
172128 }
173- } ;
129+ } catch ( e ) {
130+ console . error ( 'Failed to load note for editing:' , e ) ;
131+ showMessage ( 'Failed to load note for editing.' , { type : 'alert' } ) ;
132+ }
174133 }
175134
176- async function deleteNote ( id : number ) {
177- const transaction = db . transaction ( STORE_NAME , 'readwrite' ) ;
178- const store = transaction . objectStore ( STORE_NAME ) ;
179- store . delete ( id ) ;
180- transaction . oncomplete = ( ) => {
135+ async function handleDelete ( id : number ) {
136+ try {
137+ await deleteNote ( db , id ) ;
181138 if ( editingId === id ) resetForm ( ) ;
182139 loadNotes ( searchInput . value ) ;
183- } ;
184- }
185-
186- const removeMarkdownSyntax = ( html : string ) => {
187- let htmlContent = html . replace ( / < s p a n c l a s s = " s y n t a x - m a r k e r [ ^ " ] * " > .* ?< \/ s p a n > / g, "" ) ;
188- htmlContent = htmlContent . replace ( / \s c l a s s = " ( b u l l e t - l i s t | o r d e r e d - l i s t | c o d e - f e n c e | h r - m a r k e r | b l o c k q u o t e | u r l - p a r t ) " / g, "" ) ;
189- htmlContent = htmlContent . replace ( / \s c l a s s = " " / g, "" ) ;
190- return htmlContent ;
140+ } catch ( e ) {
141+ console . error ( 'Failed to delete note:' , e ) ;
142+ showMessage ( 'Failed to delete note.' , { type : 'alert' } ) ;
143+ }
191144 }
192145
193- async function exportToPdf ( id : number ) {
194- const transaction = db . transaction ( STORE_NAME , 'readonly' ) ;
195- const store = transaction . objectStore ( STORE_NAME ) ;
196- const request = store . get ( id ) ;
197-
198- request . onsuccess = async ( ) => {
199- const note = request . result ;
146+ async function handleExport ( id : number ) {
147+ try {
148+ const note = await getNoteById ( db , id ) ;
200149 if ( note ) {
201- // Use preview mode to output clean HTML without markdown syntax markers
202- let htmlContent = MarkdownParser . parse ( note . content ) ;
203- htmlContent = removeMarkdownSyntax ( htmlContent ) ;
204- const fullHtml = `<!DOCTYPE html>
205- <html>
206- <head>
207- <style>
208- body { font-family: sans-serif; padding: 20px; line-height: 1.5; color: #000; background: #fff; }
209- h1, h2, h3 { font-weight: bold; margin-top: 0.5em; margin-bottom: 0.2em; }
210- h1 { font-size: 1.5em; }
211- h2 { font-size: 1.25em; }
212- h3 { font-size: 1.1em; }
213- ul, ol { margin-left: 0; padding-left: 20px; }
214- .blockquote { display: block; border-left: 4px solid #ccc; padding-left: 1em; margin: 0.5em 0; opacity: 0.8; }
215- code { background-color: #f0f0f0; padding: 0.1em 0.2em; border-radius: 0.2em; font-size: 0.9em; }
216- .code-block { background-color: #f0f0f0; padding: 1em; border-radius: 0.5em; margin: 1em 0; overflow-x: auto; white-space: pre; }
217- .code-fence { opacity: 0.3; font-size: 0.8em; }
218- a { color: #0000ee; text-decoration: underline; }
219- </style>
220- </head>
221- <body>
222- ${ htmlContent }
223- </body>
224- </html>` ;
225-
226- try {
227- const pdfBytes = await htmlToPdfBuffer ( fullHtml ) ;
228- await downloadFile ( pdfBytes , `note-${ id } .pdf` , "application/pdf" ) ;
229- } catch ( e ) {
230- console . error ( "Failed to export PDF:" , e ) ;
231- showMessage ( 'Failed to export PDF. See console for details.' , { type : 'alert' } ) ;
232- }
150+ await exportNoteToPdf ( id , note . content ) ;
233151 }
234- } ;
152+ } catch ( e ) {
153+ console . error ( 'Failed to export note:' , e ) ;
154+ showMessage ( 'Failed to export note.' , { type : 'alert' } ) ;
155+ }
235156 }
236157
237- addBtn . addEventListener ( 'click' , saveNote ) ;
158+ addBtn . addEventListener ( 'click' , handleSave ) ;
238159 cancelBtn . addEventListener ( 'click' , resetForm ) ;
239160 searchInput . addEventListener ( 'input' , ( ) => loadNotes ( searchInput . value ) ) ;
240161
@@ -265,12 +186,12 @@ export default async function init() {
265186 } else if ( deleteBtn ) {
266187 const id = parseInt ( deleteBtn . getAttribute ( 'data-id' ) || '0' ) ;
267188 if ( id && confirm ( 'Delete this note?' ) ) {
268- deleteNote ( id ) ;
189+ handleDelete ( id ) ;
269190 }
270191 } else if ( target . closest ( '.export-btn' ) ) {
271192 const btn = target . closest ( '.export-btn' ) as HTMLButtonElement ;
272193 const id = parseInt ( btn . getAttribute ( 'data-id' ) || '0' ) ;
273- if ( id ) exportToPdf ( id ) ;
194+ if ( id ) handleExport ( id ) ;
274195 }
275196 } ) ;
276197
0 commit comments