updated structure

This commit is contained in:
ske087
2025-12-13 14:52:37 +02:00
parent 1a3e26d86d
commit e6193511e0
81 changed files with 0 additions and 10745 deletions

View File

@@ -0,0 +1,263 @@
// Background service worker for Chrome extension
console.log('Quality Recticel Print Helper - Background script loaded');
// Listen for messages from content script
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('Background received message:', request);
if (request.action === 'print_label') {
handlePrintLabel(request.data, sendResponse);
return true; // Keep message channel open for async response
}
if (request.action === 'fallback_print') {
handleFallbackPrint(request.data, sendResponse);
return true;
}
if (request.action === 'get_printers') {
getPrinters(sendResponse);
return true;
}
if (request.action === 'check_extension') {
sendResponse({status: 'installed', version: chrome.runtime.getManifest().version});
return true;
}
});
// Function to handle label printing
async function handlePrintLabel(printData, sendResponse) {
try {
console.log('Attempting to print label with data:', printData);
// Check if printing API is available
if (!chrome.printing || !chrome.printing.getPrinters) {
console.error('Chrome printing API not available - browser may be Brave, Edge, or older Chrome');
sendResponse({
success: false,
error: 'Direct printing API not available in this browser. The extension works best in Google Chrome 85+. Using fallback method instead.'
});
return;
}
// Get available printers
const printers = await chrome.printing.getPrinters();
console.log('Available printers:', printers);
if (printers.length === 0) {
sendResponse({success: false, error: 'No printers found. Please ensure a printer is installed and set as default.'});
return;
}
// Find selected printer or use default/first available
let selectedPrinter;
if (printData.printerId && printData.printerId !== 'default') {
selectedPrinter = printers.find(p => p.id === printData.printerId);
}
if (!selectedPrinter) {
selectedPrinter = printers.find(p => p.isDefault) || printers[0];
}
console.log('Using printer:', selectedPrinter);
// Create print job
const printJob = {
printerId: selectedPrinter.id,
ticket: {
version: '1.0',
print: {
color: {
type: 'STANDARD_MONOCHROME'
},
duplex: {
type: 'NO_DUPLEX'
},
page_orientation: {
type: 'PORTRAIT'
},
copies: {
copies: 1
},
dpi: {
horizontal_dpi: 300,
vertical_dpi: 300
},
media_size: {
width_microns: 210000, // A4 width
height_microns: 297000 // A4 height
},
collate: {
collate: false
}
}
},
documentBlob: new Blob([printData.html], {type: 'text/html'})
};
// Submit print job
const result = await chrome.printing.submitJob(printJob);
console.log('Print job result:', result);
if (result.status === 'OK') {
sendResponse({success: true, jobId: result.jobId});
// Store successful print in extension storage
chrome.storage.local.set({
lastPrint: {
timestamp: Date.now(),
jobId: result.jobId,
printer: selectedPrinter.displayName
}
});
} else {
sendResponse({success: false, error: result.status});
}
} catch (error) {
console.error('Print error:', error);
sendResponse({success: false, error: error.message});
}
}
// Function to get available printers
async function getPrinters(sendResponse) {
try {
// Check if printing API is available
if (!chrome.printing || !chrome.printing.getPrinters) {
sendResponse({
success: false,
error: 'Direct printing API not available in this browser (works in Chrome only)'
});
return;
}
const printers = await chrome.printing.getPrinters();
sendResponse({success: true, printers: printers});
} catch (error) {
console.error('Error getting printers:', error);
sendResponse({success: false, error: error.message});
}
}
// Extension installation/startup
chrome.runtime.onInstalled.addListener((details) => {
console.log('Quality Recticel Print Helper installed:', details);
// Set initial storage values
chrome.storage.local.set({
extensionVersion: chrome.runtime.getManifest().version,
installDate: Date.now()
});
});
// Fallback print method using tabs API (works in Brave, Edge, Chrome)
async function handleFallbackPrint(printData, sendResponse) {
try {
console.log('Using fallback print method for Brave/Edge/Chrome');
// Create enhanced HTML with better print styles
const enhancedHTML = `
<!DOCTYPE html>
<html>
<head>
<title>Quality Recticel Label</title>
<style>
@page {
margin: 10mm;
size: A4;
}
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background: white;
}
.print-container {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.label-wrapper {
transform: scale(1.5);
transform-origin: center;
page-break-inside: avoid;
}
@media print {
body { padding: 0; margin: 0; }
.print-container { min-height: auto; padding: 20px 0; }
.no-print { display: none !important; }
}
.print-instructions {
position: fixed;
top: 10px;
right: 10px;
background: #007bff;
color: white;
padding: 10px;
border-radius: 5px;
font-size: 14px;
z-index: 1000;
}
</style>
<script>
window.onload = function() {
// Auto-print after 1 second
setTimeout(() => {
window.print();
// Auto-close after printing (or after 10 seconds)
setTimeout(() => {
window.close();
}, 2000);
}, 1000);
};
// Handle print events
window.onbeforeprint = function() {
console.log('Print dialog opened');
};
window.onafterprint = function() {
console.log('Print dialog closed');
setTimeout(() => {
window.close();
}, 500);
};
</script>
</head>
<body>
<div class="print-instructions no-print">
🖨️ Printing will start automatically...<br>
<small>If dialog doesn't appear, press Ctrl+P</small>
</div>
<div class="print-container">
<div class="label-wrapper">
${printData.html.replace(/<!DOCTYPE html>|<html>|<\/html>|<head>.*?<\/head>|<body>|<\/body>/gi, '')}
</div>
</div>
</body>
</html>
`;
// Create a new tab with the enhanced print content
const tab = await chrome.tabs.create({
url: 'data:text/html;charset=utf-8,' + encodeURIComponent(enhancedHTML),
active: true // Make active so user can see the print dialog
});
console.log('Created print tab:', tab.id);
sendResponse({success: true, method: 'fallback_tab', tabId: tab.id});
} catch (error) {
console.error('Fallback print error:', error);
sendResponse({success: false, error: 'Browser print fallback failed: ' + error.message});
}
}
// Keep service worker alive
chrome.runtime.onConnect.addListener((port) => {
console.log('Port connected:', port.name);
});

View File

@@ -0,0 +1,301 @@
// Content script for Quality Recticel Print Helper
console.log('Quality Recticel Print Helper - Content script loaded');
// Check if we're on the print module page
if (window.location.pathname.includes('print_module')) {
console.log('Print module page detected, initializing extension features');
// Wait for DOM to be ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializePrintExtension);
} else {
initializePrintExtension();
}
}
function initializePrintExtension() {
console.log('Initializing print extension features');
// Add extension status indicator
addExtensionStatusIndicator();
// Override the print button functionality
overridePrintButton();
// Add printer selection dropdown
addPrinterSelection();
// Check extension status
checkExtensionStatus();
}
function addExtensionStatusIndicator() {
// Detect browser type
const browserType = getBrowserType();
// Create status indicator element
const statusIndicator = document.createElement('div');
statusIndicator.id = 'extension-status';
statusIndicator.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
background: ${browserType === 'chrome' ? '#28a745' : '#ffc107'};
color: ${browserType === 'chrome' ? 'white' : 'black'};
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
z-index: 9999;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
max-width: 250px;
`;
if (browserType === 'chrome') {
statusIndicator.textContent = '🖨️ Print Extension Active (Direct Print Available)';
} else {
statusIndicator.innerHTML = `🖨️ Print Extension Active<br><small>${browserType.toUpperCase()} - Browser Print Mode</small>`;
}
document.body.appendChild(statusIndicator);
// Hide after 4 seconds (longer for non-Chrome browsers)
setTimeout(() => {
statusIndicator.style.opacity = '0';
statusIndicator.style.transition = 'opacity 0.5s';
setTimeout(() => statusIndicator.remove(), 500);
}, browserType === 'chrome' ? 3000 : 5000);
}
// Detect browser type
function getBrowserType() {
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.includes('edg/')) return 'edge';
if (userAgent.includes('brave')) return 'brave';
if (userAgent.includes('chrome') && !userAgent.includes('edg/')) return 'chrome';
return 'chromium';
}
function overridePrintButton() {
// Find the print button
const printButton = document.getElementById('print-label-btn');
if (printButton) {
console.log('Found print button, overriding functionality');
// Remove existing event listeners by cloning the element
const newPrintButton = printButton.cloneNode(true);
printButton.parentNode.replaceChild(newPrintButton, printButton);
// Add new event listener for extension printing
newPrintButton.addEventListener('click', handleExtensionPrint);
// Update button text based on browser capabilities
const browserType = getBrowserType();
if (browserType === 'chrome') {
newPrintButton.innerHTML = '🖨️ Print Direct';
newPrintButton.title = 'Print directly to default printer (Chrome Extension)';
} else {
newPrintButton.innerHTML = '🖨️ Print Enhanced';
newPrintButton.title = `Enhanced printing for ${browserType.toUpperCase()} browser - Opens optimized print dialog`;
}
console.log('Print button override complete');
} else {
console.log('Print button not found, will retry...');
// Retry after 1 second if button not found yet
setTimeout(overridePrintButton, 1000);
}
}
function handleExtensionPrint(event) {
event.preventDefault();
event.stopPropagation();
console.log('Extension print button clicked');
// Get the label preview element
const labelPreview = document.getElementById('label-preview');
if (!labelPreview) {
alert('Label preview not found. Please select an order first.');
return;
}
// Show printing status
showPrintStatus('Preparing to print...', 'info');
// Create complete HTML for printing
const printHTML = createPrintableHTML(labelPreview);
// Get selected printer from dropdown
const selectedPrinterId = window.getSelectedPrinter ? window.getSelectedPrinter() : 'default';
// Try direct printing first, then fallback
chrome.runtime.sendMessage({
action: 'print_label',
data: {
html: printHTML,
timestamp: Date.now(),
printerId: selectedPrinterId
}
}, (response) => {
if (response && response.success) {
handlePrintResponse(response);
} else {
console.log('Direct printing failed, trying fallback method');
showPrintStatus('Direct printing unavailable, using browser print...', 'info');
// Try fallback method
chrome.runtime.sendMessage({
action: 'fallback_print',
data: {
html: printHTML,
timestamp: Date.now(),
printerId: selectedPrinterId
}
}, handlePrintResponse);
}
});
}
function createPrintableHTML(labelElement) {
// Get the computed styles and create a complete HTML document
const styles = `
<style>
body { margin: 0; padding: 20px; font-family: Arial, sans-serif; }
.print-container { width: 210mm; height: 297mm; margin: 0 auto; }
.label-wrapper { transform: scale(1); transform-origin: top left; }
</style>
`;
const bodyContent = `
<div class="print-container">
<div class="label-wrapper">
${labelElement.outerHTML}
</div>
</div>
`;
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Quality Recticel Label</title>
${styles}
</head>
<body>
${bodyContent}
</body>
</html>
`;
}
function handlePrintResponse(response) {
console.log('Print response:', response);
if (response && response.success) {
showPrintStatus('✅ Label sent to printer successfully!', 'success');
// Update the order status in the table if possible
updateOrderPrintStatus();
} else {
const errorMsg = response?.error || 'Unknown error occurred';
showPrintStatus(`❌ Print failed: ${errorMsg}`, 'error');
// Fallback to browser print dialog
setTimeout(() => {
if (confirm('Direct printing failed. Open browser print dialog?')) {
window.print();
}
}, 2000);
}
}
function showPrintStatus(message, type) {
// Remove existing status messages
const existingStatus = document.getElementById('print-status-message');
if (existingStatus) {
existingStatus.remove();
}
// Create status message
const statusDiv = document.createElement('div');
statusDiv.id = 'print-status-message';
statusDiv.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#17a2b8'};
color: white;
padding: 15px 25px;
border-radius: 8px;
font-size: 14px;
z-index: 10000;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
text-align: center;
min-width: 300px;
`;
statusDiv.textContent = message;
document.body.appendChild(statusDiv);
// Auto-remove after 3 seconds for success/info, 5 seconds for errors
const timeout = type === 'error' ? 5000 : 3000;
setTimeout(() => {
statusDiv.style.opacity = '0';
statusDiv.style.transition = 'opacity 0.5s';
setTimeout(() => statusDiv.remove(), 500);
}, timeout);
}
function addPrinterSelection() {
// Get available printers and add selection dropdown
chrome.runtime.sendMessage({action: 'get_printers'}, (response) => {
if (response && response.success && response.printers.length > 0) {
console.log('Available printers:', response.printers);
// Could add printer selection UI here if needed
}
});
}
function updateOrderPrintStatus() {
// Find selected row in table and update print status
const selectedRow = document.querySelector('.print-module-table tbody tr.selected');
if (selectedRow) {
const printStatusCell = selectedRow.querySelector('td:nth-last-child(2)'); // Second to last column
if (printStatusCell) {
printStatusCell.innerHTML = '<span style="color: #28a745; font-weight: bold;">✓ Yes</span>';
}
}
}
function checkExtensionStatus() {
// Verify extension is working
chrome.runtime.sendMessage({action: 'check_extension'}, (response) => {
if (response) {
console.log('Extension status:', response);
} else {
console.error('Extension communication failed');
}
});
}
// Add CSS for extension-specific styling
const extensionStyles = document.createElement('style');
extensionStyles.textContent = `
#print-label-btn {
background: linear-gradient(45deg, #28a745, #20c997) !important;
border: none !important;
transition: all 0.3s ease !important;
}
#print-label-btn:hover {
background: linear-gradient(45deg, #218838, #1ea97c) !important;
transform: translateY(-1px) !important;
box-shadow: 0 4px 8px rgba(0,0,0,0.2) !important;
}
`;
document.head.appendChild(extensionStyles);

View File

@@ -0,0 +1,7 @@
# Placeholder for icon files - in production, add actual PNG icons:
# - icon16.png (16x16 pixels)
# - icon48.png (48x48 pixels)
# - icon128.png (128x128 pixels)
# For now, create simple text-based icons using SVG converted to PNG
# These should be replaced with proper icons later

View File

@@ -0,0 +1,27 @@
# Simple text-based icons for the Chrome extension
# These are placeholder files - replace with actual PNG icons for production
# Create simple SVG icons that can be converted to PNG
ICON_16_SVG = '''
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" fill="#007bff"/>
<text x="8" y="12" font-family="Arial" font-size="10" fill="white" text-anchor="middle">🖨</text>
</svg>
'''
ICON_48_SVG = '''
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" fill="#007bff" rx="8"/>
<text x="24" y="32" font-family="Arial" font-size="24" fill="white" text-anchor="middle">🖨️</text>
</svg>
'''
ICON_128_SVG = '''
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg">
<rect width="128" height="128" fill="#007bff" rx="16"/>
<text x="64" y="84" font-family="Arial" font-size="48" fill="white" text-anchor="middle">🖨️</text>
</svg>
'''
# For now, create simple text placeholders
# In production, convert these SVGs to PNG files

View File

@@ -0,0 +1,4 @@
# Placeholder for 128x128 icon
# This is a text file placeholder
# Replace with actual icon128.png file
🖨️

View File

@@ -0,0 +1,4 @@
# Placeholder for 16x16 icon
# This is a text file placeholder
# Replace with actual icon16.png file
🖨️

View File

@@ -0,0 +1,4 @@
# Placeholder for 48x48 icon
# This is a text file placeholder
# Replace with actual icon48.png file
🖨️

View File

@@ -0,0 +1,44 @@
{
"manifest_version": 3,
"name": "Quality Recticel Print Helper",
"version": "1.0",
"description": "Direct printing extension for Quality Recticel label printing system",
"permissions": [
"activeTab",
"storage",
"tabs"
],
"optional_permissions": [
"printing"
],
"host_permissions": [
"http://localhost:*/*",
"http://127.0.0.1:*/*",
"*://*/print_module*"
],
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": [
"http://localhost:*/print_module*",
"http://127.0.0.1:*/print_module*",
"*://*/print_module*"
],
"js": ["content.js"],
"run_at": "document_end"
}
],
"action": {
"default_popup": "popup.html",
"default_title": "Quality Recticel Print Helper"
},
"web_accessible_resources": [
{
"resources": ["content.js"],
"matches": ["<all_urls>"]
}
]
}

View File

@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Quality Recticel Print Helper</title>
<style>
body {
width: 300px;
padding: 15px;
font-family: Arial, sans-serif;
margin: 0;
}
.header {
text-align: center;
margin-bottom: 15px;
}
.logo {
font-size: 24px;
margin-bottom: 5px;
}
.title {
font-weight: bold;
font-size: 14px;
margin-bottom: 3px;
}
.version {
font-size: 11px;
color: #666;
}
.status {
background: #e8f5e8;
border: 1px solid #28a745;
color: #28a745;
padding: 8px;
border-radius: 4px;
font-size: 12px;
text-align: center;
margin: 10px 0;
}
.info {
font-size: 12px;
line-height: 1.4;
color: #555;
margin: 10px 0;
}
.button {
width: 100%;
padding: 8px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 5px 0;
font-size: 12px;
}
.button:hover {
background: #0056b3;
}
.button.secondary {
background: #6c757d;
}
.button.secondary:hover {
background: #545b62;
}
</style>
</head>
<body>
<div class="header">
<div class="logo">🖨️</div>
<div class="title">Quality Recticel Print Helper</div>
<div class="version">Version 1.0</div>
</div>
<div class="status">
✅ Extension Active
</div>
<div class="info">
This extension enables direct printing from the Quality Recticel label system to your default printer without browser dialogs.
</div>
<button class="button" id="test-print">Test Print Connection</button>
<button class="button secondary" id="open-settings">Printer Settings</button>
<div class="info">
<strong>Usage:</strong> Navigate to the Print Module page and use the enhanced print button for direct printing.
</div>
<script src="popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,29 @@
// Popup script for Quality Recticel Print Helper
document.addEventListener('DOMContentLoaded', function() {
console.log('Popup loaded');
// Test print button
document.getElementById('test-print').addEventListener('click', function() {
chrome.runtime.sendMessage({action: 'get_printers'}, function(response) {
if (response && response.success) {
if (response.printers.length > 0) {
alert(`✅ Found ${response.printers.length} printer(s):\n${response.printers.map(p => p.displayName).join('\n')}`);
} else {
alert('⚠️ No printers found. Please ensure a printer is installed and set as default.');
}
} else {
const error = response?.error || 'Unknown error';
if (error.includes('Chrome printing API not available')) {
alert('⚠️ Chrome Printing API not available.\n\nThis may be due to:\n• Chrome version too old (need 85+)\n• Extension permissions not granted\n• Corporate/managed Chrome installation\n\nThe extension will use browser print dialog as fallback.');
} else {
alert('❌ Error getting printers: ' + error);
}
}
});
});
// Settings button
document.getElementById('open-settings').addEventListener('click', function() {
chrome.tabs.create({url: 'chrome://settings/printing'});
});
});