add meta data to guide & improve error handling

This commit is contained in:
Michi 2024-11-09 20:20:36 +01:00
parent 1fcbe7b968
commit b574265e65
5 changed files with 108 additions and 36 deletions

View file

@ -12,10 +12,11 @@ Similar to tango.us/dubble.so/folge.me/magichow.co but all local - no data leave
- [x] create basic popup UI - [x] create basic popup UI
### Additional nice to have: ### Additional nice to have:
- [x] Meta data in guide (title, description, author, date)
- [ ] Viewer for Guide JSON - [ ] Viewer for Guide JSON
- [ ] PDF export - [ ] PDF export
- [ ] Editor for Guide - [ ] Editor for Guide
- [ ] improve error handling - [x] improve error handling
- [ ] Blur sensitive information - [ ] Blur sensitive information
- [x] Pause/resume recording feature - [x] Pause/resume recording feature

View file

@ -1,20 +1,33 @@
// Background Worker // Background Worker
const dateToday = new Date().toISOString().split('T')[0];
let guide = {
"title":"Guide",
"description":"",
"date":dateToday,
"author":"Me",
};
let steps = []; let steps = [];
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
switch(message.action){ switch(message.action){
case "captureScreenshot": case "captureScreenshot":
chrome.tabs.captureVisibleTab(null, { format: "jpeg" }, (dataUrl) => { try{
if (chrome.runtime.lastError) { chrome.tabs.captureVisibleTab(null, { format: "jpeg" }, (dataUrl) => {
console.error("Error capturing screenshot: ", chrome.runtime.lastError); if (chrome.runtime.lastError) {
sendResponse({ success: false, error: chrome.runtime.lastError }); console.error("Error capturing screenshot: ", chrome.runtime.lastError);
return; sendResponse({ success: false, error: chrome.runtime.lastError });
} return;
}
sendResponse({ success: true, screenshot: dataUrl });
}); sendResponse({ success: true, screenshot: dataUrl });
return true; });
return true;
}
catch(error){
return sendResponse({ success: false, message: error });
}
case "saveStep": case "saveStep":
try{ try{
const step = { const step = {
@ -31,14 +44,35 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
return sendResponse({ success: false, message: error }); return sendResponse({ success: false, message: error });
} }
case "generateGuide": case "generateGuide":
return sendResponse({ success: true, guide: steps }); try{
let filename = "guide.json";
chrome.storage.local.get(["guideTitle", "exportFilename"], (data) => {
if(data.guideTitle) guide.title = `Guide: ${data.guideTitle}`;
if(data.exportFilename) filename = `guide-${data.exportFilename}.json`;
guide.steps = steps;
return sendResponse({ success: true, guide: guide, filename: filename });
});
return true;
}
catch(error){
return sendResponse({ success: false, message: error });
}
case "clearGuide": case "clearGuide":
steps = []; try{
return sendResponse({ success: true, message: "Cleared guide successfully" }); steps = [];
return sendResponse({ success: true, message: "Cleared guide successfully" });
}
catch(error){
return sendResponse({ success: false, message: error });
}
case "guideLenght": case "guideLenght":
count = steps.length; try{
return sendResponse({ success: true, stepCount: count }); count = steps.length;
case "debug": return sendResponse({ success: true, stepCount: count });
}
catch(error){
return sendResponse({ success: false, message: error });
}
default: default:
console.log(message.action); console.log(message.action);
break; break;

View file

@ -1,5 +1,22 @@
// Script which is executed on all web pages // Script which is executed on all web pages
// Page meta data
const pageTitle = document.title;
const domainFormatted = window.location.host.replace(/\./g, "-");
// set guide title
chrome.storage.local.get("guideTitle", (data) => {
if(!data.guideTitle){
try{
chrome.storage.local.set({ guideTitle: pageTitle });
chrome.storage.local.set({ exportFilename: domainFormatted });
}
catch(error){
console.error(`Error while saving guide metadata: ${error}`)
}
}
});
// load recording status & react to updates // load recording status & react to updates
let isRecording = false; let isRecording = false;
chrome.storage.local.get("recording", (data) => { chrome.storage.local.get("recording", (data) => {

View file

@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "Cl1ck Gu1de", "name": "Cl1ck Gu1de",
"version": "0.0.3", "version": "0.0.4",
"description": "A browser add-on which records the steps clicked on a page and generates a easy to understand guide from it.", "description": "A browser add-on which records the steps clicked on a page and generates a easy to understand guide from it.",
"permissions": ["scripting", "activeTab", "downloads", "tabs", "storage"], "permissions": ["scripting", "activeTab", "downloads", "tabs", "storage"],
"host_permissions": ["<all_urls>"], "host_permissions": ["<all_urls>"],

View file

@ -4,7 +4,6 @@
let isRecording = false; let isRecording = false;
chrome.storage.local.get("recording", (data) => { chrome.storage.local.get("recording", (data) => {
isRecording = data.recording || false; isRecording = data.recording || false;
console.log(data);
updateRecordingLabel(isRecording); updateRecordingLabel(isRecording);
}); });
@ -13,10 +12,14 @@ const toggleRecordingBtn = document.getElementById("toggleRecording");
const exportBtn = document.getElementById("exportBtn"); const exportBtn = document.getElementById("exportBtn");
toggleRecordingBtn.addEventListener('click', () => { toggleRecordingBtn.addEventListener('click', () => {
//if(isRecording) chrome.runtime.sendMessage({action: "clearGuide"}); try{
isRecording = !isRecording; // toggle status isRecording = !isRecording; // toggle status
updateRecordingLabel(isRecording); // update label updateRecordingLabel(isRecording); // update label
chrome.storage.local.set({ recording: isRecording }); // save status chrome.storage.local.set({ recording: isRecording }); // save status
}
catch(error){
console.error(`Got error on toggling recording: ${error}`)
}
}); });
exportBtn.addEventListener('click', () => { exportBtn.addEventListener('click', () => {
@ -24,8 +27,14 @@ exportBtn.addEventListener('click', () => {
chrome.runtime.sendMessage({ chrome.runtime.sendMessage({
action: "generateGuide" action: "generateGuide"
}, (response) => { }, (response) => {
const guide = response.guide; if(response.success){
exportJSON(guide, "guide.json"); const guide = response.guide;
const filename = response.filename;
return exportJSON(guide, filename);
}
else{
console.error(`Failed to export guide: ${response.message} `);
}
}); });
}); });
@ -48,18 +57,29 @@ function updateRecordingLabel(bool){
// export guide as json // export guide as json
function exportJSON(object, filename){ function exportJSON(object, filename){
const json = JSON.stringify(object, null, 2); try{
const json = JSON.stringify(object, null, 2);
const blob = new Blob([json], { type: "application/json" }); const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
}
catch(error){
return error
}
const link = document.createElement("a");
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url); try{
// clear guide
// clear guide return chrome.runtime.sendMessage({action: "clearGuide"});
chrome.runtime.sendMessage({action: "clearGuide"}); }
catch(error){
return error
}
} }