first version of browser extension hireflow
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
const TRACKER_FILE = "content/tracker.js";
|
||||
|
||||
function storageGet(keys) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.get(keys, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function storageSet(obj) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.set(obj, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function storageRemove(keys) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.storage.local.remove(keys, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function tabsQuery(queryInfo) {
|
||||
return new Promise((resolve) => {
|
||||
chrome.tabs.query(queryInfo, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
function executeScript(details) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.scripting.executeScript(details, () => {
|
||||
const err = chrome.runtime.lastError;
|
||||
if (err) {
|
||||
reject(new Error(err.message));
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const els = {
|
||||
record: document.getElementById("record"),
|
||||
stop: document.getElementById("stop"),
|
||||
exportSection: document.getElementById("export-section"),
|
||||
exportJson: document.getElementById("export-json"),
|
||||
copy: document.getElementById("copy"),
|
||||
copyStatus: document.getElementById("copy-status"),
|
||||
hint: document.getElementById("hint"),
|
||||
navHint: document.getElementById("nav-hint"),
|
||||
};
|
||||
|
||||
function isRestrictedUrl(url) {
|
||||
if (!url) {
|
||||
return true;
|
||||
}
|
||||
const u = url.toLowerCase();
|
||||
return (
|
||||
u.startsWith("chrome://") ||
|
||||
u.startsWith("chrome-extension://") ||
|
||||
u.startsWith("edge://") ||
|
||||
u.startsWith("about:") ||
|
||||
u.startsWith("moz-extension://") ||
|
||||
u.startsWith("devtools:") ||
|
||||
u.startsWith("view-source:")
|
||||
);
|
||||
}
|
||||
|
||||
async function getActiveTab() {
|
||||
const tabs = await tabsQuery({ active: true, currentWindow: true });
|
||||
return tabs[0];
|
||||
}
|
||||
|
||||
async function injectTracker(tabId) {
|
||||
await executeScript({
|
||||
target: { tabId },
|
||||
files: [TRACKER_FILE],
|
||||
});
|
||||
}
|
||||
|
||||
function sendToTab(tabId, message) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.tabs.sendMessage(tabId, message, (response) => {
|
||||
const err = chrome.runtime.lastError;
|
||||
if (err) {
|
||||
reject(new Error(err.message));
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function clearRecordingStorage() {
|
||||
await storageRemove(["recording", "recordingTabId"]);
|
||||
}
|
||||
|
||||
function setRecordingUi(isRecording, showExport) {
|
||||
els.record.classList.toggle("hidden", isRecording);
|
||||
els.stop.classList.toggle("hidden", !isRecording);
|
||||
els.stop.disabled = !isRecording;
|
||||
els.navHint.classList.toggle("hidden", !isRecording);
|
||||
els.exportSection.classList.toggle("hidden", !showExport);
|
||||
}
|
||||
|
||||
async function syncStateFromTab() {
|
||||
const tab = await getActiveTab();
|
||||
const data = await storageGet(["recording", "recordingTabId"]);
|
||||
|
||||
if (!tab?.id) {
|
||||
setRecordingUi(false, !!els.exportJson.value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.recording || data.recordingTabId !== tab.id) {
|
||||
setRecordingUi(false, !!els.exportJson.value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRestrictedUrl(tab.url)) {
|
||||
await clearRecordingStorage();
|
||||
setRecordingUi(false, !!els.exportJson.value);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await injectTracker(tab.id);
|
||||
const status = await sendToTab(tab.id, { type: "GET_STATUS" });
|
||||
if (status && status.recording) {
|
||||
setRecordingUi(true, !!els.exportJson.value);
|
||||
} else {
|
||||
await clearRecordingStorage();
|
||||
setRecordingUi(false, !!els.exportJson.value);
|
||||
}
|
||||
} catch {
|
||||
await clearRecordingStorage();
|
||||
setRecordingUi(false, !!els.exportJson.value);
|
||||
}
|
||||
}
|
||||
|
||||
els.record.addEventListener("click", async () => {
|
||||
els.copyStatus.textContent = "";
|
||||
const tab = await getActiveTab();
|
||||
if (!tab?.id) {
|
||||
return;
|
||||
}
|
||||
if (isRestrictedUrl(tab.url)) {
|
||||
els.hint.textContent =
|
||||
"Opnemen werkt niet op deze pagina (browser-interne URL). Open een normale website.";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await injectTracker(tab.id);
|
||||
await sendToTab(tab.id, { type: "START_RECORDING" });
|
||||
await storageSet({
|
||||
recording: true,
|
||||
recordingTabId: tab.id,
|
||||
});
|
||||
els.exportJson.value = "";
|
||||
setRecordingUi(true, false);
|
||||
els.hint.textContent =
|
||||
"Interacties worden vastgelegd. Druk op Stop om de JSON te tonen.";
|
||||
} catch (e) {
|
||||
els.hint.textContent =
|
||||
"Kon niet starten: ververs de pagina of controleer of de site scripts toestaat.";
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
els.stop.addEventListener("click", async () => {
|
||||
els.copyStatus.textContent = "";
|
||||
const tab = await getActiveTab();
|
||||
const data = await storageGet(["recordingTabId"]);
|
||||
|
||||
if (!tab?.id || tab.id !== data.recordingTabId) {
|
||||
await clearRecordingStorage();
|
||||
setRecordingUi(false, false);
|
||||
els.hint.textContent = "Geen actieve opname op dit tabblad.";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await injectTracker(tab.id);
|
||||
const response = await sendToTab(tab.id, {
|
||||
type: "STOP_AND_GET_INTERACTIONS",
|
||||
});
|
||||
await clearRecordingStorage();
|
||||
|
||||
const interactions = response?.interactions ?? [];
|
||||
els.exportJson.value = JSON.stringify(interactions, null, 2);
|
||||
setRecordingUi(false, true);
|
||||
els.hint.textContent =
|
||||
"JSON hieronder. Gebruik Kopiëren of selecteer de tekst handmatig.";
|
||||
} catch (e) {
|
||||
await clearRecordingStorage();
|
||||
setRecordingUi(false, false);
|
||||
els.hint.textContent =
|
||||
"Stoppen mislukt (pagina mogelijk vernieuwd). Start opnieuw met Opnemen.";
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
els.copy.addEventListener("click", async () => {
|
||||
const text = els.exportJson.value;
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
els.copyStatus.textContent = "Gekopieerd naar klembord.";
|
||||
} catch {
|
||||
els.exportJson.select();
|
||||
els.copyStatus.textContent = "Selecteer Cmd/Ctrl+C om te kopiëren.";
|
||||
}
|
||||
});
|
||||
|
||||
syncStateFromTab();
|
||||
Reference in New Issue
Block a user