diff --git a/TODO.md b/TODO.md index e04e18d..8e73f6c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ Only immediate next things to do are listed here, without any far-fetching plans. -- Implement syncing local storage with service worker (either via postMessage or using IndexedDB) - Implement reminders - Implement masonry layout - Implement color coding diff --git a/js/db-store.js b/js/db-store.js new file mode 100644 index 0000000..7fdeda6 --- /dev/null +++ b/js/db-store.js @@ -0,0 +1,139 @@ +export class DBNoteStore extends EventTarget { + constructor(dbName, storeName) { + super(); + this.dbName = dbName; + this.storeName = storeName; + this.db = null; + } + + async all() { + const that = this; + return this.#connect().then( + (db) => + new Promise((resolve, reject) => { + db + .transaction([that.storeName], "readonly") + .objectStore(that.storeName) + .getAll().onsuccess = (data) => resolve(data.target.result); + }), + ); + } + + async get(id) { + const that = this; + let result; + + return this.#connect().then( + (db) => + new Promise( + (resolve, reject) => + (db + .transaction([that.storeName], "readonly") + .objectStore(that.storeName) + .get(id).onsuccess = (data) => resolve(data.target.result)), + ), + ); + } + + async add(note) { + const that = this; + + const entry = { + id: "id_" + Date.now(), + type: note.type, + content: note.content, + created: new Date(), + }; + + return this.#connect().then( + (db) => + new Promise( + (resolve, reject) => + (db + .transaction([that.storeName], "readwrite") + .objectStore(that.storeName) + .add(entry).onsuccess = () => resolve(null)), + ), + ); + } + + async reset() { + const that = this; + + return this.#connect().then( + (db) => + new Promise( + (resolve, reject) => + (db + .transaction([that.storeName], "readwrite") + .objectStore(that.storeName) + .clear().onsuccess = () => resolve(null)), + ), + ); + } + + async remove({ id }) { + const that = this; + + return this.#connect().then( + (db) => + new Promise( + (resolve, reject) => + (db + .transaction([that.storeName], "readwrite") + .objectStore(that.storeName) + .delete(id).onsuccess = () => resolve(null)), + ), + ); + } + + async update(note) { + const that = this; + + return this.#connect().then( + (db) => + new Promise( + (resolve, reject) => + (db + .transaction([that.storeName], "readwrite") + .objectStore(that.storeName) + .put(note).onsuccess = () => resolve(null)), + ), + ); + } + + saveStorage() { + this.dispatchEvent(new CustomEvent("save")); + } + + async #connect() { + if (!this.db) { + this.db = await this.#dbConnect(); + } + + return this.db; + } + + #dbConnect() { + const that = this; + + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.dbName, 1); + + request.onsuccess = (e) => { + resolve(e.target.result); + }; + + request.onerror = (e) => { + console.error(`indexedDB error: ${e.target.errorCode}`); + }; + + request.onupgradeneeded = (e) => { + const db = e.target.result; + db.createObjectStore(that.storeName, { + keyPath: "id", + }); + }; + }); + } +} diff --git a/js/jenot.js b/js/jenot.js index 1a8c813..f080690 100644 --- a/js/jenot.js +++ b/js/jenot.js @@ -1,9 +1,14 @@ import "./service-worker.js"; import { renderText } from "./dom.js"; import { NoteStore } from "./store.js"; +import { DBNoteStore } from "./db-store.js"; import "./components.js"; -const Notes = new NoteStore("jenot-app"); +const urlParams = new URLSearchParams(window.location.search); + +const Notes = urlParams.has("localStorage") + ? new NoteStore("jenot-app") + : new DBNoteStore("jenot-app", "notes"); const newNote = document.querySelector("#new-note"); const editNote = document.querySelector("#edit-note"); @@ -12,28 +17,27 @@ Notes.addEventListener("save", render.bind(this)); render(); -newNote.addEventListener("addNote", (e) => { - console.log(e.detail); - Notes.add(e.detail); +newNote.addEventListener("addNote", async (e) => { + await Notes.add(e.detail); Notes.saveStorage(); }); -editNote.addEventListener("updateNote", (e) => { +editNote.addEventListener("updateNote", async (e) => { newNote.classList.remove("hidden"); editNote.classList.add("hidden"); - Notes.update(e.detail); + await Notes.update(e.detail); Notes.saveStorage(); }); -editNote.addEventListener("deleteNote", (e) => { +editNote.addEventListener("deleteNote", async (e) => { newNote.classList.remove("hidden"); editNote.classList.add("hidden"); - Notes.remove(e.detail); + await Notes.remove(e.detail); Notes.saveStorage(); }); -function render() { - const notes = Notes.all(); +async function render() { + const notes = await Notes.all(); const notesContainer = document.querySelector("#notes"); notesContainer.replaceChildren(); @@ -64,10 +68,11 @@ function render() { notesContainer.appendChild(container); - container.addEventListener("click", (e) => { + container.addEventListener("click", async (e) => { newNote.classList.add("hidden"); editNote.classList.remove("hidden"); - editNote.load(Notes.get(container.id)); + const note = await Notes.get(container.id); + editNote.load(note); }); }); } diff --git a/js/store.js b/js/store.js index 343fcdf..8fb440f 100644 --- a/js/store.js +++ b/js/store.js @@ -1,7 +1,6 @@ export class NoteStore extends EventTarget { localStorageKey; notes = []; - editedNoteId = "none"; /* Note structure: @@ -31,7 +30,6 @@ export class NoteStore extends EventTarget { all = () => this.notes; get = (id) => this.notes.find((note) => note.id === id); - getEditedNoteId = () => this.editedNoteId; add(note) { this.notes.unshift({ @@ -54,19 +52,11 @@ export class NoteStore extends EventTarget { this.notes = this.notes.map((n) => (n.id === note.id ? note : n)); } - setEditedNoteId(id) { - this.editedNoteId = id; - } - saveStorage() { window.localStorage.setItem( this.localStorageKey + "_notes", JSON.stringify(this.notes), ); - window.localStorage.setItem( - this.localStorageKey + "_editedNoteId", - this.editedNoteId, - ); this.dispatchEvent(new CustomEvent("save")); } @@ -74,8 +64,5 @@ export class NoteStore extends EventTarget { this.notes = JSON.parse( window.localStorage.getItem(this.localStorageKey + "_notes") || "[]", ); - this.editedNoteId = - window.localStorage.getItem(this.localStorageKey + "_editedNoteId") || - "none"; } }