-
Notifications
You must be signed in to change notification settings - Fork 0
/
background.js
130 lines (109 loc) · 4.27 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
'use strict';
// Configuration constants - kept for edge cases
const CONFIG = {
TRANSPARENT_COLORS: ['rgba(0, 0, 0, 0)', 'transparent', ''],
EXCLUDED_URLS: ['about:blank', 'about:newtab'],
CSS_VARS: ['--background-color', '--bg-color', '--backgroundColor'],
CLASS_PATTERNS: {
PREFIX: ['bg-', 'background-'],
CONTAINS: ['has-background']
}
};
// Setup handler
const handleInstallation = (details) => {
if (details.reason === "install") {
browser.tabs.create({ url: "setup.html" });
}
};
// Optimized injection code
const createInjectionCode = () => `
(function() {
const CONFIG = ${JSON.stringify(CONFIG)};
// Cache DOM elements and styles
const html = document.documentElement;
const body = document.body;
function checkBackground() {
if (!html || !body) return;
// Cache computed styles (reduces calls)
const htmlStyle = getComputedStyle(html);
const bodyStyle = getComputedStyle(body);
// Quick transparent check
const isTransparent = color => CONFIG.TRANSPARENT_COLORS.includes(color);
if (!isTransparent(htmlStyle.backgroundColor) || !isTransparent(bodyStyle.backgroundColor)) {
return;
}
// Quick class check using native methods
const hasBackgroundClass = element => {
const classList = element.classList;
return CONFIG.CLASS_PATTERNS.PREFIX.some(prefix =>
Array.from(classList).some(cls => cls.startsWith(prefix))
) || CONFIG.CLASS_PATTERNS.CONTAINS.some(pattern =>
Array.from(classList).some(cls => cls.includes(pattern))
);
};
// Check for CSS variables (cached styles)
const hasCustomProperty = element => {
const style = getComputedStyle(element);
return CONFIG.CSS_VARS.some(prop => style.getPropertyValue(prop).trim());
};
// Inline style check
const hasInlineBackground = element => {
const style = element.getAttribute('style');
return style && (style.includes('background') || style.includes('bg-'));
};
// Only proceed if no background is found
if (!hasCustomProperty(html) && !hasCustomProperty(body) &&
!hasInlineBackground(html) && !hasInlineBackground(body) &&
!hasBackgroundClass(html) && !hasBackgroundClass(body)) {
// Apply background only once
if (!html.classList.contains('blanko-background')) {
const style = document.createElement('style');
style.textContent = '.blanko-background{background-color:white!important}';
(document.head || html).appendChild(style);
html.classList.add('blanko-background');
}
}
}
// Initial check
checkBackground();
// Check once DOM is loaded
document.addEventListener('DOMContentLoaded', checkBackground, { once: true });
// Add MutationObserver for dynamic content
const observer = new MutationObserver((mutations) => {
requestAnimationFrame(checkBackground);
});
// Start observing once DOM is ready
document.addEventListener('DOMContentLoaded', () => {
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['style', 'class']
});
});
// Cleanup observer after 30 seconds to prevent memory leaks
setTimeout(() => observer.disconnect(), 30000);
})();
`;
// Simplified URL validation
const isValidUrl = url => url && !CONFIG.EXCLUDED_URLS.some(excluded => url.startsWith(excluded));
// Simplified error handling
const handleError = (error, tabId) => {
if (!error.message?.includes('Missing host permission') &&
!error.message?.includes('Cannot access')) {
console.error(`Injection failed for tab ${tabId}: `, error);
}
};
// Optimized tab update handler
const handleTabUpdate = (tabId, changeInfo, tab) => {
if ((changeInfo.status === 'loading' || changeInfo.status === 'complete') &&
isValidUrl(tab.url)) {
browser.tabs.executeScript(tabId, {
code: createInjectionCode(),
runAt: 'document_start'
}).catch(error => handleError(error, tabId));
}
};
// Event listeners
browser.runtime.onInstalled.addListener(handleInstallation);
browser.tabs.onUpdated.addListener(handleTabUpdate);