Updated to print service power shell
This commit is contained in:
299
windows_print_service/chrome_extension/background.js
Normal file
299
windows_print_service/chrome_extension/background.js
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* Quality Recticel Print Service - Background Script
|
||||
* Handles communication between web pages and Windows print service
|
||||
*/
|
||||
|
||||
// Configuration
|
||||
const PRINT_SERVICE_URL = 'http://localhost:8765';
|
||||
const SERVICE_CHECK_INTERVAL = 30000; // 30 seconds
|
||||
|
||||
// Service status
|
||||
let serviceStatus = {
|
||||
available: false,
|
||||
lastCheck: null,
|
||||
printers: []
|
||||
};
|
||||
|
||||
// Initialize extension
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
console.log('Quality Recticel Print Service extension installed');
|
||||
checkServiceStatus();
|
||||
|
||||
// Set up periodic service check
|
||||
setInterval(checkServiceStatus, SERVICE_CHECK_INTERVAL);
|
||||
});
|
||||
|
||||
// Handle messages from content scripts or web pages
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
console.log('Background script received message:', message);
|
||||
|
||||
switch (message.action) {
|
||||
case 'print_pdf':
|
||||
handlePrintPDF(message.data).then(sendResponse);
|
||||
return true; // Keep message channel open for async response
|
||||
|
||||
case 'silent_print':
|
||||
handleSilentPrint(message.data).then(sendResponse);
|
||||
return true;
|
||||
|
||||
case 'get_printers':
|
||||
handleGetPrinters().then(sendResponse);
|
||||
return true;
|
||||
|
||||
case 'check_service':
|
||||
checkServiceStatus().then(sendResponse);
|
||||
return true;
|
||||
|
||||
default:
|
||||
sendResponse({ error: 'Unknown action', success: false });
|
||||
}
|
||||
});
|
||||
|
||||
// Handle external messages from web pages
|
||||
chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
|
||||
console.log('External message received:', message, 'from:', sender);
|
||||
|
||||
// Verify sender origin for security
|
||||
const allowedOrigins = [
|
||||
'http://localhost:5000',
|
||||
'http://localhost:8000',
|
||||
'http://127.0.0.1:5000',
|
||||
'http://127.0.0.1:8000'
|
||||
];
|
||||
|
||||
if (!allowedOrigins.includes(sender.origin)) {
|
||||
sendResponse({ error: 'Unauthorized origin', success: false });
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the message
|
||||
switch (message.action) {
|
||||
case 'print_pdf':
|
||||
case 'silent_print':
|
||||
handleSilentPrint(message.data).then(sendResponse);
|
||||
return true;
|
||||
|
||||
case 'get_printers':
|
||||
handleGetPrinters().then(sendResponse);
|
||||
return true;
|
||||
|
||||
case 'ping':
|
||||
sendResponse({
|
||||
success: true,
|
||||
service_available: serviceStatus.available,
|
||||
extension_version: chrome.runtime.getManifest().version
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
sendResponse({ error: 'Unknown action', success: false });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the Windows print service is available
|
||||
*/
|
||||
async function checkServiceStatus() {
|
||||
try {
|
||||
const response = await fetch(`${PRINT_SERVICE_URL}/health`, {
|
||||
method: 'GET',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
serviceStatus.available = true;
|
||||
serviceStatus.lastCheck = new Date();
|
||||
|
||||
console.log('Print service is available:', data);
|
||||
|
||||
// Update extension badge
|
||||
chrome.action.setBadgeText({ text: '✓' });
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#28a745' });
|
||||
|
||||
return { success: true, status: data };
|
||||
} else {
|
||||
throw new Error(`Service returned status ${response.status}`);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn('Print service not available:', error);
|
||||
|
||||
serviceStatus.available = false;
|
||||
serviceStatus.lastCheck = new Date();
|
||||
|
||||
// Update extension badge
|
||||
chrome.action.setBadgeText({ text: '✗' });
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#dc3545' });
|
||||
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle PDF printing request
|
||||
*/
|
||||
async function handlePrintPDF(printData) {
|
||||
try {
|
||||
if (!serviceStatus.available) {
|
||||
await checkServiceStatus();
|
||||
|
||||
if (!serviceStatus.available) {
|
||||
throw new Error('Print service is not available');
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(`${PRINT_SERVICE_URL}/print/pdf`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(printData)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
console.log('Print job completed:', result);
|
||||
|
||||
// Show notification
|
||||
chrome.notifications.create({
|
||||
type: 'basic',
|
||||
iconUrl: 'icons/icon48.png',
|
||||
title: 'Quality Recticel Print Service',
|
||||
message: 'PDF printed successfully'
|
||||
});
|
||||
|
||||
return { success: true, result };
|
||||
} else {
|
||||
throw new Error(result.error || 'Print job failed');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Print PDF error:', error);
|
||||
|
||||
// Show error notification
|
||||
chrome.notifications.create({
|
||||
type: 'basic',
|
||||
iconUrl: 'icons/icon48.png',
|
||||
title: 'Quality Recticel Print Service',
|
||||
message: `Print failed: ${error.message}`
|
||||
});
|
||||
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle silent printing request
|
||||
*/
|
||||
async function handleSilentPrint(printData) {
|
||||
try {
|
||||
if (!serviceStatus.available) {
|
||||
await checkServiceStatus();
|
||||
|
||||
if (!serviceStatus.available) {
|
||||
// Try direct browser printing as fallback
|
||||
return await handleDirectPrint(printData);
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(`${PRINT_SERVICE_URL}/print/silent`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(printData)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
console.log('Silent print completed:', result);
|
||||
return { success: true, result };
|
||||
} else {
|
||||
throw new Error(result.error || 'Silent print failed');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Silent print error:', error);
|
||||
|
||||
// Fallback to direct printing
|
||||
return await handleDirectPrint(printData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle direct browser printing (fallback)
|
||||
*/
|
||||
async function handleDirectPrint(printData) {
|
||||
try {
|
||||
// Create hidden iframe for printing
|
||||
const printFrame = document.createElement('iframe');
|
||||
printFrame.style.display = 'none';
|
||||
printFrame.src = printData.pdf_url || 'data:application/pdf;base64,' + printData.pdf_data;
|
||||
|
||||
document.body.appendChild(printFrame);
|
||||
|
||||
// Wait for load and print
|
||||
return new Promise((resolve) => {
|
||||
printFrame.onload = () => {
|
||||
setTimeout(() => {
|
||||
printFrame.contentWindow.print();
|
||||
document.body.removeChild(printFrame);
|
||||
resolve({ success: true, method: 'browser_fallback' });
|
||||
}, 1000);
|
||||
};
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Direct print error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available printers
|
||||
*/
|
||||
async function handleGetPrinters() {
|
||||
try {
|
||||
if (!serviceStatus.available) {
|
||||
await checkServiceStatus();
|
||||
|
||||
if (!serviceStatus.available) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Print service not available',
|
||||
printers: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(`${PRINT_SERVICE_URL}/printers`, {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
serviceStatus.printers = result.printers || [];
|
||||
return { success: true, printers: result.printers };
|
||||
} else {
|
||||
throw new Error(result.error || 'Failed to get printers');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Get printers error:', error);
|
||||
return { success: false, error: error.message, printers: [] };
|
||||
}
|
||||
}
|
||||
|
||||
// Export for testing
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
checkServiceStatus,
|
||||
handlePrintPDF,
|
||||
handleSilentPrint,
|
||||
handleGetPrinters
|
||||
};
|
||||
}
|
||||
232
windows_print_service/chrome_extension/content.js
Normal file
232
windows_print_service/chrome_extension/content.js
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Quality Recticel Print Service - Content Script
|
||||
* Injects print service functionality into web pages
|
||||
*/
|
||||
|
||||
// Only inject on Quality Recticel domains or localhost
|
||||
const allowedDomains = [
|
||||
'localhost',
|
||||
'127.0.0.1'
|
||||
];
|
||||
|
||||
const currentDomain = window.location.hostname;
|
||||
if (!allowedDomains.includes(currentDomain)) {
|
||||
console.log('Quality Recticel Print Service: Not injecting on', currentDomain);
|
||||
// return; // Commented out for development - remove in production
|
||||
}
|
||||
|
||||
console.log('Quality Recticel Print Service: Content script loaded');
|
||||
|
||||
// Inject print service API into the page
|
||||
const printServiceAPI = {
|
||||
|
||||
/**
|
||||
* Print PDF via the service
|
||||
*/
|
||||
async printPDF(printData) {
|
||||
try {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'print_pdf',
|
||||
data: printData
|
||||
}, resolve);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Print PDF error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Silent print PDF
|
||||
*/
|
||||
async silentPrint(printData) {
|
||||
try {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'silent_print',
|
||||
data: printData
|
||||
}, resolve);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Silent print error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get available printers
|
||||
*/
|
||||
async getPrinters() {
|
||||
try {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'get_printers'
|
||||
}, resolve);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Get printers error:', error);
|
||||
return { success: false, error: error.message, printers: [] };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check service status
|
||||
*/
|
||||
async checkService() {
|
||||
try {
|
||||
return new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'check_service'
|
||||
}, resolve);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Check service error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Print labels with Quality Recticel specific formatting
|
||||
*/
|
||||
async printLabels(orderData, quantity = 1) {
|
||||
try {
|
||||
// Generate PDF URL for the labels
|
||||
const pdfUrl = `/generate_labels_pdf/${orderData.order_id}`;
|
||||
|
||||
const printData = {
|
||||
pdf_url: window.location.origin + pdfUrl,
|
||||
printer_name: 'default',
|
||||
copies: 1,
|
||||
order_id: orderData.order_id,
|
||||
quantity: quantity,
|
||||
silent: true
|
||||
};
|
||||
|
||||
return await this.silentPrint(printData);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Print labels error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Make API available globally
|
||||
window.QualityRecticelPrintService = printServiceAPI;
|
||||
|
||||
// Inject into page context for better compatibility
|
||||
const script = document.createElement('script');
|
||||
script.textContent = `
|
||||
// Quality Recticel Print Service API
|
||||
window.QualityRecticelPrintService = ${JSON.stringify(printServiceAPI)};
|
||||
|
||||
// Enhanced print function for Quality Recticel
|
||||
window.printQualityRecticelLabels = async function(orderData, quantity) {
|
||||
try {
|
||||
// Get the PDF blob from the server
|
||||
const response = await fetch('/generate_labels_pdf/' + orderData.order_id, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to generate PDF');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
|
||||
// Convert to base64
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = async () => {
|
||||
const base64Data = reader.result.split(',')[1];
|
||||
|
||||
const printData = {
|
||||
pdf_data: base64Data,
|
||||
printer_name: 'default',
|
||||
copies: 1,
|
||||
silent: true
|
||||
};
|
||||
|
||||
// Send message to content script
|
||||
const result = await new Promise((msgResolve) => {
|
||||
window.postMessage({
|
||||
type: 'QUALITY_RECTICEL_PRINT',
|
||||
action: 'silent_print',
|
||||
data: printData
|
||||
}, '*');
|
||||
|
||||
// Listen for response
|
||||
const listener = (event) => {
|
||||
if (event.data.type === 'QUALITY_RECTICEL_PRINT_RESPONSE') {
|
||||
window.removeEventListener('message', listener);
|
||||
msgResolve(event.data.result);
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
});
|
||||
|
||||
resolve(result);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Print Quality Recticel labels error:', error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Quality Recticel Print Service API injected');
|
||||
`;
|
||||
document.documentElement.appendChild(script);
|
||||
|
||||
// Listen for messages from injected script
|
||||
window.addEventListener('message', async (event) => {
|
||||
if (event.source !== window) return;
|
||||
|
||||
if (event.data.type === 'QUALITY_RECTICEL_PRINT') {
|
||||
try {
|
||||
let result;
|
||||
|
||||
switch (event.data.action) {
|
||||
case 'silent_print':
|
||||
result = await printServiceAPI.silentPrint(event.data.data);
|
||||
break;
|
||||
case 'print_pdf':
|
||||
result = await printServiceAPI.printPDF(event.data.data);
|
||||
break;
|
||||
case 'get_printers':
|
||||
result = await printServiceAPI.getPrinters();
|
||||
break;
|
||||
default:
|
||||
result = { success: false, error: 'Unknown action' };
|
||||
}
|
||||
|
||||
// Send response back
|
||||
window.postMessage({
|
||||
type: 'QUALITY_RECTICEL_PRINT_RESPONSE',
|
||||
result: result
|
||||
}, '*');
|
||||
|
||||
} catch (error) {
|
||||
window.postMessage({
|
||||
type: 'QUALITY_RECTICEL_PRINT_RESPONSE',
|
||||
result: { success: false, error: error.message }
|
||||
}, '*');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Notify page that extension is ready
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.dispatchEvent(new CustomEvent('QualityRecticelPrintServiceReady', {
|
||||
detail: {
|
||||
version: chrome.runtime.getManifest().version,
|
||||
api: printServiceAPI
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
console.log('Quality Recticel Print Service: Content script initialized');
|
||||
59
windows_print_service/chrome_extension/manifest.json
Normal file
59
windows_print_service/chrome_extension/manifest.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Quality Recticel Print Service",
|
||||
"version": "1.0.0",
|
||||
"description": "Silent PDF printing service for Quality Recticel application",
|
||||
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"storage",
|
||||
"nativeMessaging",
|
||||
"printingMetrics"
|
||||
],
|
||||
|
||||
"host_permissions": [
|
||||
"http://localhost:*/*",
|
||||
"https://localhost:*/*"
|
||||
],
|
||||
|
||||
"background": {
|
||||
"service_worker": "background.js",
|
||||
"type": "module"
|
||||
},
|
||||
|
||||
"content_scripts": [{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content.js"],
|
||||
"run_at": "document_end"
|
||||
}],
|
||||
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_title": "Quality Recticel Print Service",
|
||||
"default_icon": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
}
|
||||
},
|
||||
|
||||
"icons": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/icon32.png",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
},
|
||||
|
||||
"web_accessible_resources": [{
|
||||
"resources": ["content.js"],
|
||||
"matches": ["<all_urls>"]
|
||||
}],
|
||||
|
||||
"externally_connectable": {
|
||||
"matches": [
|
||||
"http://localhost:*/*",
|
||||
"https://localhost:*/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
196
windows_print_service/chrome_extension/popup.html
Normal file
196
windows_print_service/chrome_extension/popup.html
Normal file
@@ -0,0 +1,196 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body {
|
||||
width: 350px;
|
||||
min-height: 200px;
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #f8f9fa;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin: 0 auto 8px;
|
||||
background: #007bff;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.version {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.status-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
border-left: 4px solid #28a745;
|
||||
}
|
||||
|
||||
.status-card.error {
|
||||
border-left-color: #dc3545;
|
||||
}
|
||||
|
||||
.status-card.warning {
|
||||
border-left-color: #ffc107;
|
||||
}
|
||||
|
||||
.status-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.status-message {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.status-detail {
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.button {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 8px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
.button:disabled {
|
||||
background: #6c757d;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.button.secondary {
|
||||
background: #6c757d;
|
||||
}
|
||||
|
||||
.button.secondary:hover {
|
||||
background: #545b62;
|
||||
}
|
||||
|
||||
.printers-list {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.printer-item {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.printer-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.printer-name {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.printer-details {
|
||||
color: #666;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
font-size: 11px;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="logo">QR</div>
|
||||
<div class="title">Quality Recticel Print Service</div>
|
||||
<div class="version">Version 1.0.0</div>
|
||||
</div>
|
||||
|
||||
<div id="loading" class="loading">
|
||||
<div>Checking service status...</div>
|
||||
</div>
|
||||
|
||||
<div id="content" class="hidden">
|
||||
<div id="service-status" class="status-card">
|
||||
<div class="status-title">Print Service Status</div>
|
||||
<div class="status-message" id="status-message">Checking...</div>
|
||||
<div class="status-detail" id="status-detail"></div>
|
||||
</div>
|
||||
|
||||
<button id="refresh-btn" class="button">Refresh Status</button>
|
||||
<button id="test-print-btn" class="button">Test Print</button>
|
||||
<button id="get-printers-btn" class="button secondary">Get Printers</button>
|
||||
|
||||
<div id="printers-container" class="hidden">
|
||||
<div class="printers-list">
|
||||
<div style="font-weight: 600; margin-bottom: 8px; font-size: 14px;">Available Printers</div>
|
||||
<div id="printers-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<a href="#" id="help-link" class="footer-link">Help & Documentation</a>
|
||||
</div>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
261
windows_print_service/chrome_extension/popup.js
Normal file
261
windows_print_service/chrome_extension/popup.js
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Quality Recticel Print Service - Popup Script
|
||||
* Manages the extension popup interface
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('Popup loaded');
|
||||
|
||||
// Get elements
|
||||
const elements = {
|
||||
loading: document.getElementById('loading'),
|
||||
content: document.getElementById('content'),
|
||||
serviceStatus: document.getElementById('service-status'),
|
||||
statusMessage: document.getElementById('status-message'),
|
||||
statusDetail: document.getElementById('status-detail'),
|
||||
refreshBtn: document.getElementById('refresh-btn'),
|
||||
testPrintBtn: document.getElementById('test-print-btn'),
|
||||
getPrintersBtn: document.getElementById('get-printers-btn'),
|
||||
printersContainer: document.getElementById('printers-container'),
|
||||
printersList: document.getElementById('printers-list'),
|
||||
helpLink: document.getElementById('help-link')
|
||||
};
|
||||
|
||||
// Initialize popup
|
||||
await initializePopup();
|
||||
|
||||
// Event listeners
|
||||
elements.refreshBtn.addEventListener('click', checkServiceStatus);
|
||||
elements.testPrintBtn.addEventListener('click', testPrint);
|
||||
elements.getPrintersBtn.addEventListener('click', getPrinters);
|
||||
elements.helpLink.addEventListener('click', showHelp);
|
||||
|
||||
/**
|
||||
* Initialize popup
|
||||
*/
|
||||
async function initializePopup() {
|
||||
try {
|
||||
await checkServiceStatus();
|
||||
|
||||
// Show content, hide loading
|
||||
elements.loading.classList.add('hidden');
|
||||
elements.content.classList.remove('hidden');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Initialization error:', error);
|
||||
showError('Failed to initialize popup');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check service status
|
||||
*/
|
||||
async function checkServiceStatus() {
|
||||
try {
|
||||
elements.refreshBtn.disabled = true;
|
||||
elements.refreshBtn.textContent = 'Checking...';
|
||||
|
||||
// Send message to background script
|
||||
const result = await new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ action: 'check_service' }, resolve);
|
||||
});
|
||||
|
||||
updateServiceStatus(result);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Service check error:', error);
|
||||
showError('Failed to check service status');
|
||||
} finally {
|
||||
elements.refreshBtn.disabled = false;
|
||||
elements.refreshBtn.textContent = 'Refresh Status';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update service status display
|
||||
*/
|
||||
function updateServiceStatus(result) {
|
||||
const statusCard = elements.serviceStatus;
|
||||
const message = elements.statusMessage;
|
||||
const detail = elements.statusDetail;
|
||||
|
||||
if (result && result.success) {
|
||||
// Service is available
|
||||
statusCard.className = 'status-card';
|
||||
message.textContent = 'Service is running normally';
|
||||
detail.textContent = `Last checked: ${new Date().toLocaleTimeString()}`;
|
||||
|
||||
// Enable buttons
|
||||
elements.testPrintBtn.disabled = false;
|
||||
elements.getPrintersBtn.disabled = false;
|
||||
|
||||
} else {
|
||||
// Service is not available
|
||||
statusCard.className = 'status-card error';
|
||||
message.textContent = 'Service is not available';
|
||||
detail.textContent = result ? result.error : 'Unknown error';
|
||||
|
||||
// Disable buttons
|
||||
elements.testPrintBtn.disabled = true;
|
||||
elements.getPrintersBtn.disabled = false; // Keep enabled for diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test print functionality
|
||||
*/
|
||||
async function testPrint() {
|
||||
try {
|
||||
elements.testPrintBtn.disabled = true;
|
||||
elements.testPrintBtn.textContent = 'Testing...';
|
||||
|
||||
// Create test PDF data
|
||||
const testPrintData = {
|
||||
pdf_url: 'data:application/pdf;base64,JVBERi0xLjQKMSAwIG9iago8PAovVGl0bGUgKFRlc3QgUGFnZSkKL0NyZWF0b3IgKFF1YWxpdHkgUmVjdGljZWwgUHJpbnQgU2VydmljZSkKL1Byb2R1Y2VyIChRdWFsaXR5IFJlY3RpY2VsKQovQ3JlYXRpb25EYXRlIChEOjIwMjMwMTAxMTIwMDAwKQo+PgplbmRvYmoKMiAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMyAwIFIKPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFs0IDAgUl0KL0NvdW50IDEKPJ4KZW5kb2JqCjQgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAzIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovQ29udGVudHMgNSAwIFIKL1Jlc291cmNlcyA8PAovRm9udCA8PAovRjEgNiAwIFIKPj4KPj4KPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0xlbmd0aCA0NAo+PgpzdHJlYW0KQlQKL0YxIDEyIFRmCjEwMCA3MDAgVGQKKFRlc3QgUHJpbnQgUGFnZSkgVGoKRVQKZW5kc3RyZWFtCmVuZG9iago2IDAgb2JqCjw8Ci9UeXBlIC9Gb250Ci9TdWJ0eXBlIC9UeXBlMQovQmFzZUZvbnQgL0hlbHZldGljYQo+PgplbmRvYmoKeHJlZgowIDcKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDA5IDAwMDAwIG4gCjAwMDAwMDAxNDggMDAwMDAgbiAKMDAwMDAwMDE5NSAwMDAwMCBuIAowMDAwMDAwMjUyIDAwMDAwIG4gCjAwMDAwMDA0MTQgMDAwMDAgbiAKMDAwMDAwMDUwOCAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDcKL1Jvb3QgMiAwIFIKL0luZm8gMSAwIFIKPj4Kc3RhcnR4cmVmCjU2NQolJUVPRgo=',
|
||||
printer_name: 'default',
|
||||
copies: 1
|
||||
};
|
||||
|
||||
// Send test print request
|
||||
const result = await new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'print_pdf',
|
||||
data: testPrintData
|
||||
}, resolve);
|
||||
});
|
||||
|
||||
if (result && result.success) {
|
||||
showSuccess('Test print sent successfully');
|
||||
} else {
|
||||
showError(result ? result.error : 'Test print failed');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Test print error:', error);
|
||||
showError('Test print failed: ' + error.message);
|
||||
} finally {
|
||||
elements.testPrintBtn.disabled = false;
|
||||
elements.testPrintBtn.textContent = 'Test Print';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available printers
|
||||
*/
|
||||
async function getPrinters() {
|
||||
try {
|
||||
elements.getPrintersBtn.disabled = true;
|
||||
elements.getPrintersBtn.textContent = 'Loading...';
|
||||
|
||||
// Get printers from background script
|
||||
const result = await new Promise((resolve) => {
|
||||
chrome.runtime.sendMessage({ action: 'get_printers' }, resolve);
|
||||
});
|
||||
|
||||
if (result && result.success && result.printers) {
|
||||
displayPrinters(result.printers);
|
||||
} else {
|
||||
showError(result ? result.error : 'Failed to get printers');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Get printers error:', error);
|
||||
showError('Failed to get printers: ' + error.message);
|
||||
} finally {
|
||||
elements.getPrintersBtn.disabled = false;
|
||||
elements.getPrintersBtn.textContent = 'Get Printers';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display printers list
|
||||
*/
|
||||
function displayPrinters(printers) {
|
||||
if (!printers || printers.length === 0) {
|
||||
elements.printersList.innerHTML = '<div style="color: #666; font-style: italic;">No printers found</div>';
|
||||
} else {
|
||||
elements.printersList.innerHTML = printers.map(printer => `
|
||||
<div class="printer-item">
|
||||
<div class="printer-name">${escapeHtml(printer.name)}</div>
|
||||
<div class="printer-details">
|
||||
Driver: ${escapeHtml(printer.driver || 'Unknown')}<br>
|
||||
Port: ${escapeHtml(printer.port || 'Unknown')}
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
elements.printersContainer.classList.remove('hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show success message
|
||||
*/
|
||||
function showSuccess(message) {
|
||||
const statusCard = elements.serviceStatus;
|
||||
const statusMessage = elements.statusMessage;
|
||||
const statusDetail = elements.statusDetail;
|
||||
|
||||
statusCard.className = 'status-card';
|
||||
statusMessage.textContent = message;
|
||||
statusDetail.textContent = new Date().toLocaleTimeString();
|
||||
|
||||
// Reset after 3 seconds
|
||||
setTimeout(() => {
|
||||
checkServiceStatus();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error message
|
||||
*/
|
||||
function showError(message) {
|
||||
const statusCard = elements.serviceStatus;
|
||||
const statusMessage = elements.statusMessage;
|
||||
const statusDetail = elements.statusDetail;
|
||||
|
||||
statusCard.className = 'status-card error';
|
||||
statusMessage.textContent = 'Error: ' + message;
|
||||
statusDetail.textContent = new Date().toLocaleTimeString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show help information
|
||||
*/
|
||||
function showHelp() {
|
||||
const helpText = `
|
||||
Quality Recticel Print Service Help
|
||||
==================================
|
||||
|
||||
Installation:
|
||||
1. Install the Windows Print Service using install_service.bat
|
||||
2. Install this Chrome extension
|
||||
3. Configure your application to use localhost:8765
|
||||
|
||||
API Endpoints:
|
||||
• http://localhost:8765/health - Service health check
|
||||
• http://localhost:8765/print/pdf - Print PDF files
|
||||
• http://localhost:8765/print/silent - Silent printing
|
||||
• http://localhost:8765/printers - Get available printers
|
||||
|
||||
Troubleshooting:
|
||||
• Ensure Windows service is running
|
||||
• Check firewall settings (port 8765)
|
||||
• Verify Chrome extension permissions
|
||||
• Check service logs: print_service.log
|
||||
|
||||
For support, contact the Quality Recticel development team.
|
||||
`;
|
||||
|
||||
alert(helpText.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML to prevent XSS
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user