Initial commit

This commit is contained in:
Tibo De Peuter 2026-08-08 17:35:53 +02:00
commit 4ae6b27809
No known key found for this signature in database
GPG key ID: 9187B5FA0F4B6F6D
4 changed files with 137 additions and 0 deletions

13
background.js Normal file
View file

@ -0,0 +1,13 @@
browser.action.onClicked.addListener((tab) => {
// Inject the CSS for the hover highlight
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["content.css"]
});
// Inject the JavaScript for the element picker
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["content.js"]
});
});

6
content.css Normal file
View file

@ -0,0 +1,6 @@
.pep-hover-highlight {
outline: 3px dashed #0088ff !important;
outline-offset: -3px !important;
cursor: crosshair !important;
background-color: rgba(0, 136, 255, 0.1) !important;
}

100
content.js Normal file
View file

@ -0,0 +1,100 @@
(function() {
if (window.pepActive) return;
window.pepActive = true;
let currentHovered = null;
function handleMouseOver(e) {
e.stopPropagation();
if (currentHovered) {
currentHovered.classList.remove('pep-hover-highlight');
}
currentHovered = e.target;
currentHovered.classList.add('pep-hover-highlight');
}
function handleMouseOut(e) {
e.stopPropagation();
if (currentHovered) {
currentHovered.classList.remove('pep-hover-highlight');
currentHovered = null;
}
}
function handleClick(e) {
e.preventDefault();
e.stopPropagation();
// Turn off picker mode
document.removeEventListener('mouseover', handleMouseOver, true);
document.removeEventListener('mouseout', handleMouseOut, true);
document.removeEventListener('click', handleClick, true);
window.pepActive = false;
if (currentHovered) {
currentHovered.classList.remove('pep-hover-highlight');
printElement(currentHovered);
}
}
function printElement(el) {
el.classList.add('pep-print-target');
// Walk up the DOM tree to tag all ancestors of the target
let current = el.parentElement;
const ancestors = [];
while (current && current !== document.body && current !== document.documentElement) {
current.classList.add('pep-print-ancestor');
ancestors.push(current);
current = current.parentElement;
}
// Inject CSS that hides siblings of the target and siblings of its ancestors
const style = document.createElement('style');
style.textContent = `
@media print {
/* Hide all siblings of the body, ancestors, and target */
body > *:not(.pep-print-ancestor):not(.pep-print-target),
.pep-print-ancestor > *:not(.pep-print-ancestor):not(.pep-print-target) {
display: none !important;
}
/* Strip formatting from ancestors to prevent them from pushing the target around */
.pep-print-ancestor {
padding: 0 !important;
margin: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
position: static !important;
overflow: visible !important;
}
/* Reset body constraints */
body {
padding: 0 !important;
margin: 0 !important;
min-height: 100vh !important;
}
}
`;
document.head.appendChild(style);
// Short delay to ensure browser applies the print CSS before opening dialog
setTimeout(() => {
window.print();
// Clean up the temporary styles and classes after the print dialog closes
setTimeout(() => {
el.classList.remove('pep-print-target');
ancestors.forEach(a => a.classList.remove('pep-print-ancestor'));
style.remove();
}, 1000);
}, 100);
}
// Activate event listeners in the capture phase to override default page behaviors
document.addEventListener('mouseover', handleMouseOver, true);
document.addEventListener('mouseout', handleMouseOut, true);
document.addEventListener('click', handleClick, true);
})();

18
manifest.json Normal file
View file

@ -0,0 +1,18 @@
{
"manifest_version": 3,
"name": "Print Element Picker",
"version": "1.0",
"description": "Interactively pick an element on the page and print only that element.",
"permissions": ["activeTab", "scripting"],
"action": {
"default_title": "Pick element to print"
},
"background": {
"scripts": ["background.js"]
},
"browser_specific_settings": {
"gecko": {
"id": "print-picker@yourdomain.com"
}
}
}