Last active
September 26, 2025 14:19
-
-
Save casparjones/c65189c45a9295803ded9b57e9b528ef to your computer and use it in GitHub Desktop.
Lebenslauf PouchDB Manager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Lebenslauf PouchDB Manager | |
| // @namespace https://lebenslauf.com/ | |
| // @version 0.4.0 | |
| // @description Save & Restore vita-document and preferences with PouchDB + CouchDB Sync + User Selector Popup | |
| // @author Frank | |
| // @match https://lebenslauf.com/neu | |
| // @icon https://www.google.com/s2/favicons?sz=64&domain=lebenslauf.com | |
| // @grant none | |
| // @require https://cdn.jsdelivr.net/npm/pouchdb@8.0.1/dist/pouchdb.min.js | |
| // @updateURL https://gist.githubusercontent.com/casparjones/c65189c45a9295803ded9b57e9b528ef/raw/lebenslauf_pouchDBManager.user.js | |
| // @downloadURL https://gist.githubusercontent.com/casparjones/c65189c45a9295803ded9b57e9b528ef/raw/lebenslauf_pouchDBManager.user.js | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // --- Init PouchDB --- | |
| let db = new PouchDB('lebenslauf_vita'); | |
| // --- UI Buttons --- | |
| function addButton(text, onclick, color = "lightblue") { | |
| let btn = document.createElement("button"); | |
| btn.innerText = text; | |
| btn.style.position = "fixed"; | |
| btn.style.top = `${50 + document.querySelectorAll(".vita-btn").length * 40}px`; | |
| btn.style.right = "20px"; | |
| btn.style.zIndex = 9999; | |
| btn.style.background = color; | |
| btn.style.padding = "8px"; | |
| btn.style.border = "1px solid #333"; | |
| btn.classList.add("vita-btn"); | |
| btn.onclick = onclick; | |
| document.body.appendChild(btn); | |
| } | |
| // --- Popup --- | |
| function showPopup(allDocs) { | |
| let overlay = document.createElement("div"); | |
| overlay.style.position = "fixed"; | |
| overlay.style.top = "0"; | |
| overlay.style.left = "0"; | |
| overlay.style.width = "100%"; | |
| overlay.style.height = "100%"; | |
| overlay.style.background = "rgba(0,0,0,0.5)"; | |
| overlay.style.zIndex = "10000"; | |
| overlay.id = "vita-overlay"; | |
| let popup = document.createElement("div"); | |
| popup.style.position = "fixed"; | |
| popup.style.top = "50%"; | |
| popup.style.left = "50%"; | |
| popup.style.transform = "translate(-50%, -50%)"; | |
| popup.style.background = "#fff"; | |
| popup.style.padding = "20px"; | |
| popup.style.border = "2px solid #333"; | |
| popup.style.borderRadius = "8px"; | |
| popup.style.minWidth = "300px"; | |
| popup.style.textAlign = "center"; | |
| let title = document.createElement("h3"); | |
| title.innerText = "Person wiederherstellen"; | |
| popup.appendChild(title); | |
| let select = document.createElement("select"); | |
| select.style.width = "100%"; | |
| select.style.margin = "10px 0"; | |
| allDocs.rows.forEach(row => { | |
| let opt = document.createElement("option"); | |
| opt.value = row.doc._id; | |
| opt.textContent = `${row.doc._id} (${row.doc.ts || "kein Datum"})`; | |
| select.appendChild(opt); | |
| }); | |
| popup.appendChild(select); | |
| let btnSync = document.createElement("button"); | |
| btnSync.innerText = "Person wiederherstellen"; | |
| btnSync.style.marginRight = "10px"; | |
| btnSync.onclick = async () => { | |
| let id = select.value; | |
| let person = await db.get(id); | |
| localStorage.setItem('vita-document', JSON.stringify(person.document)); | |
| localStorage.setItem('vita-cover-letter', JSON.stringify(person.letter)); | |
| localStorage.setItem('vita-preferences', JSON.stringify(person.preferences)); | |
| alert(`Person ${person._id} wiederhergestellt!`); | |
| document.body.removeChild(overlay); | |
| location.reload(); | |
| }; | |
| let btnClose = document.createElement("button"); | |
| btnClose.innerText = "Abbrechen"; | |
| btnClose.onclick = () => { | |
| document.body.removeChild(overlay); | |
| }; | |
| popup.appendChild(btnSync); | |
| popup.appendChild(btnClose); | |
| overlay.appendChild(popup); | |
| document.body.appendChild(overlay); | |
| } | |
| // --- Save Config --- | |
| addButton("Save Config", async () => { | |
| let data = JSON.parse(localStorage.getItem('vita-document') || "{}"); | |
| let letter = JSON.parse(localStorage.getItem('vita-cover-letter') || "{}"); | |
| let preferences = JSON.parse(localStorage.getItem('vita-preferences') || "{}"); | |
| if (!data?.cv?.personalInformation?.firstName) { | |
| alert("Kein Vorname gefunden!"); | |
| return; | |
| } | |
| let doc = { | |
| _id: data.cv.personalInformation.firstName, | |
| document: data, | |
| preferences: preferences, | |
| letter: letter, | |
| ts: new Date().toISOString() | |
| }; | |
| try { | |
| await db.put(doc); | |
| alert("Config gespeichert!"); | |
| } catch (e) { | |
| if (e.name === 'conflict') { | |
| let existing = await db.get(doc._id); | |
| doc._rev = existing._rev; | |
| await db.put(doc); | |
| alert("Config aktualisiert!"); | |
| } else { | |
| console.error(e); | |
| alert("Fehler beim Speichern!"); | |
| } | |
| } | |
| }); | |
| // --- Restore Personen (mit Popup) --- | |
| addButton("Restore Personen", async () => { | |
| try { | |
| let allDocs = await db.allDocs({ include_docs: true }); | |
| if (allDocs.rows.length === 0) { | |
| alert("Keine gespeicherten Personen gefunden!"); | |
| return; | |
| } | |
| showPopup(allDocs); | |
| } catch (e) { | |
| console.error(e); | |
| alert("Fehler beim Wiederherstellen!"); | |
| } | |
| }); | |
| // --- Set CouchDB URL --- | |
| addButton("Set CouchDB URL", async () => { | |
| let couchUrl = prompt("CouchDB-URL eingeben (z.B. http://user:pass@localhost:5984/lebenslauf_vita):", localStorage.getItem("couchdb_url") || ""); | |
| if (couchUrl) { | |
| localStorage.setItem("couchdb_url", couchUrl); | |
| alert("CouchDB-URL gespeichert!"); | |
| // Sync starten | |
| let remoteDB = new PouchDB(couchUrl); | |
| db.sync(remoteDB, { live: true, retry: true }) | |
| .on('change', info => console.log("Sync change:", info)) | |
| .on('error', err => console.error("Sync error:", err)); | |
| } | |
| }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment