open-web-inspector
Version:
The open source web element inspector - AI-controllable DOM inspection with live CSS editing, hover highlighting, and developer tools integration
206 lines (179 loc) • 7.18 kB
JavaScript
// Open Web Inspector Extension Popup Script
document.addEventListener('DOMContentLoaded', async () => {
const elements = {
loading: document.getElementById('loading'),
content: document.getElementById('content'),
status: document.getElementById('status'),
statusText: document.getElementById('status-text'),
versionBadge: document.getElementById('version-badge'),
toggleBtn: document.getElementById('toggleBtn'),
enableBtn: document.getElementById('enableBtn'),
disableBtn: document.getElementById('disableBtn')
};
let currentTab = null;
/**
* Get the current active tab
*/
async function getCurrentTab() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
return tab;
}
/**
* Send message to content script
*/
async function sendMessage(action, data = {}) {
if (!currentTab) {
throw new Error('No active tab available');
}
return new Promise((resolve, reject) => {
chrome.tabs.sendMessage(currentTab.id, { action, ...data }, (response) => {
if (chrome.runtime.lastError) {
reject(new Error(chrome.runtime.lastError.message));
} else {
resolve(response);
}
});
});
}
/**
* Update the UI status
*/
function updateStatus(loaded, active, version = null) {
// Update status container classes
elements.status.classList.remove('loaded', 'not-loaded', 'active');
if (!loaded) {
elements.status.classList.add('not-loaded');
elements.statusText.textContent = 'Inspector not loaded';
elements.versionBadge.textContent = '';
} else if (active) {
elements.status.classList.add('active');
elements.statusText.textContent = 'Inspector ACTIVE';
elements.versionBadge.textContent = version ? `v${version}` : '';
} else {
elements.status.classList.add('loaded');
elements.statusText.textContent = 'Inspector ready';
elements.versionBadge.textContent = version ? `v${version}` : '';
}
// Update button states
elements.toggleBtn.disabled = !loaded;
elements.enableBtn.disabled = !loaded || active;
elements.disableBtn.disabled = !loaded || !active;
// Update button text
if (loaded) {
elements.toggleBtn.textContent = active ? 'Disable Inspector' : 'Enable Inspector';
} else {
elements.toggleBtn.textContent = 'Inspector Not Loaded';
}
}
/**
* Check the current status
*/
async function checkStatus() {
try {
const response = await sendMessage('status');
if (response && response.success) {
updateStatus(response.loaded, response.active, response.version);
} else {
updateStatus(false, false);
}
} catch (error) {
console.error('Failed to check status:', error);
updateStatus(false, false);
}
}
/**
* Show notification
*/
function showNotification(message, type = 'info') {
// Create a temporary notification (you could enhance this)
const originalText = elements.statusText.textContent;
elements.statusText.textContent = message;
setTimeout(() => {
checkStatus(); // Refresh status after action
}, 1000);
}
/**
* Handle button clicks
*/
elements.toggleBtn.addEventListener('click', async () => {
try {
elements.toggleBtn.disabled = true;
const response = await sendMessage('toggle');
if (response && response.success) {
showNotification(response.message, 'success');
} else {
showNotification('Failed to toggle inspector', 'error');
}
} catch (error) {
console.error('Toggle failed:', error);
showNotification('Extension communication error', 'error');
} finally {
elements.toggleBtn.disabled = false;
}
});
elements.enableBtn.addEventListener('click', async () => {
try {
elements.enableBtn.disabled = true;
const response = await sendMessage('enable');
if (response && response.success) {
showNotification('Inspector enabled!', 'success');
} else {
showNotification('Failed to enable inspector', 'error');
}
} catch (error) {
console.error('Enable failed:', error);
showNotification('Extension communication error', 'error');
} finally {
elements.enableBtn.disabled = false;
}
});
elements.disableBtn.addEventListener('click', async () => {
try {
elements.disableBtn.disabled = true;
const response = await sendMessage('disable');
if (response && response.success) {
showNotification('Inspector disabled', 'success');
} else {
showNotification('Failed to disable inspector', 'error');
}
} catch (error) {
console.error('Disable failed:', error);
showNotification('Extension communication error', 'error');
} finally {
elements.disableBtn.disabled = false;
}
});
// Initialize
try {
currentTab = await getCurrentTab();
if (!currentTab) {
throw new Error('No active tab found');
}
// Check if this is a valid web page
if (!currentTab.url || currentTab.url.startsWith('chrome://') || currentTab.url.startsWith('chrome-extension://')) {
elements.loading.style.display = 'none';
elements.content.innerHTML = `
<div style="text-align: center; padding: 20px; color: #6c757d;">
<p>⚠️ Cannot inject inspector</p>
<p style="font-size: 12px;">Extension pages and system pages are not supported</p>
</div>
`;
elements.content.style.display = 'block';
return;
}
// Hide loading and show content
elements.loading.style.display = 'none';
elements.content.style.display = 'block';
// Check initial status
await checkStatus();
// Set up periodic status refresh
const statusInterval = setInterval(checkStatus, 2000);
// Clean up when popup closes
window.addEventListener('beforeunload', () => {
clearInterval(statusInterval);
});
} catch (error) {
console.error('Popup initialization failed:', error);
elements.loading.textContent = 'Failed to connect to page';
}
});