This repository has been archived on 2026-05-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
GallerySubscriber/extension/popup/popup.js
T

296 lines
8.0 KiB
JavaScript

/**
* Popup script - handles UI interactions
*/
document.addEventListener('DOMContentLoaded', async () => {
await init();
});
/**
* Initialize the popup
*/
async function init() {
// Check configuration
const config = await browser.runtime.sendMessage({ type: 'GET_CONFIG' });
if (!config.apiUrl || !config.apiKey) {
showSetupRequired();
return;
}
// Test connection
const connectionStatus = await browser.runtime.sendMessage({ type: 'TEST_CONNECTION' });
updateConnectionIndicator(connectionStatus.connected);
// Show main content
document.getElementById('setup-required').classList.add('hidden');
document.getElementById('main-content').classList.remove('hidden');
if (!connectionStatus.connected) {
showError(`Cannot connect to backend: ${connectionStatus.error}`);
}
// Load platform status
await loadPlatformStatus();
// Setup event listeners
setupEventListeners();
}
/**
* Show the setup required message
*/
function showSetupRequired() {
document.getElementById('setup-required').classList.remove('hidden');
document.getElementById('main-content').classList.add('hidden');
document.getElementById('open-settings-btn').addEventListener('click', () => {
browser.runtime.openOptionsPage();
});
}
/**
* Update the connection status indicator
* @param {boolean} connected - Whether connected to backend
*/
function updateConnectionIndicator(connected) {
const indicator = document.getElementById('connection-status');
indicator.classList.toggle('connected', connected);
indicator.title = connected ? 'Connected to GallerySubscriber' : 'Disconnected';
}
/**
* Load and display platform status
*/
async function loadPlatformStatus() {
const status = await browser.runtime.sendMessage({ type: 'GET_PLATFORM_STATUS' });
const container = document.getElementById('platforms-list');
container.innerHTML = '';
for (const [key, platform] of Object.entries(PLATFORMS)) {
const platformStatus = status[key] || {};
const card = createPlatformCard(key, platform, platformStatus);
container.appendChild(card);
}
}
/**
* Create a platform card element
* @param {string} key - Platform key
* @param {object} platform - Platform definition
* @param {object} status - Platform status
* @returns {HTMLElement}
*/
function createPlatformCard(key, platform, status) {
const card = document.createElement('div');
card.className = 'platform-card';
card.dataset.platform = key;
// Discord is clickable if we have a token captured
// Other token-based platforms are disabled
const isDisabled = platform.authType === 'token' && key !== 'discord';
const isDiscordWithoutToken = key === 'discord' && !status.hasToken;
if (isDisabled || isDiscordWithoutToken) {
card.classList.add('disabled');
}
const statusText = getStatusText(status, platform, key);
const statusClass = getStatusClass(status, platform, key);
card.innerHTML = `
<div class="platform-icon" style="background-color: ${platform.color}">
${platform.name.charAt(0)}
</div>
<div class="info">
<div class="name">${platform.name}</div>
<div class="status ${statusClass}">${statusText}</div>
</div>
<span class="action-icon">
<svg width="20" height="20" viewBox="0 0 24 24">
<path fill="currentColor" d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"/>
</svg>
</span>
`;
if (!isDisabled && !isDiscordWithoutToken) {
card.addEventListener('click', () => exportPlatformCookies(key, card));
}
return card;
}
/**
* Get status text for display
* @param {object} status - Platform status
* @param {object} platform - Platform definition
* @param {string} key - Platform key
* @returns {string}
*/
function getStatusText(status, platform, key) {
// Special handling for Discord token-based auth
if (key === 'discord') {
if (status.hasToken) {
return 'Token captured - ready to export';
}
return 'Open Discord in browser to capture token';
}
if (platform.authType === 'token') {
return 'Manual token entry required';
}
if (status.error) {
return 'Error checking cookies';
}
if (!status.hasCookies || status.cookieCount === 0) {
return 'No cookies found - log in first';
}
return `${status.cookieCount} cookies ready`;
}
/**
* Get status CSS class
* @param {object} status - Platform status
* @param {object} platform - Platform definition
* @param {string} key - Platform key
* @returns {string}
*/
function getStatusClass(status, platform, key) {
// Special handling for Discord
if (key === 'discord') {
return status.hasToken ? 'ready' : 'no-cookies';
}
if (platform.authType === 'token') {
return 'no-cookies';
}
if (status.error) {
return 'error';
}
if (!status.hasCookies || status.cookieCount === 0) {
return 'no-cookies';
}
return 'ready';
}
/**
* Export cookies for a single platform
* @param {string} platformKey - Platform key
* @param {HTMLElement} cardElement - The card element
*/
async function exportPlatformCookies(platformKey, cardElement) {
cardElement.classList.add('loading');
hideStatusMessage();
try {
const result = await browser.runtime.sendMessage({
type: 'EXPORT_COOKIES',
platform: platformKey
});
if (result.error) {
showError(result.error);
} else {
// Handle different response types (cookies vs token)
const successMsg = result.cookieCount !== undefined
? `${PLATFORMS[platformKey].name}: ${result.cookieCount} cookies exported!`
: `${PLATFORMS[platformKey].name}: Token exported successfully!`;
showSuccess(successMsg);
// Refresh status
await loadPlatformStatus();
}
} catch (error) {
showError(error.message);
} finally {
cardElement.classList.remove('loading');
}
}
/**
* Export cookies for all platforms
*/
async function exportAllCookies() {
const btn = document.getElementById('export-all-btn');
btn.disabled = true;
btn.textContent = 'Exporting...';
hideStatusMessage();
try {
const results = await browser.runtime.sendMessage({ type: 'EXPORT_ALL_COOKIES' });
const successes = Object.values(results).filter(r => r.success).length;
const skipped = Object.values(results).filter(r => r.skipped).length;
const failures = Object.values(results).filter(r => !r.success && !r.skipped).length;
if (failures === 0 && successes > 0) {
showSuccess(`Exported ${successes} platform(s) successfully!`);
} else if (successes > 0) {
showWarning(`${successes} succeeded, ${failures} failed`);
} else if (failures > 0) {
showError('All exports failed. Are you logged in?');
} else {
showWarning('No platforms to export');
}
await loadPlatformStatus();
} catch (error) {
showError(error.message);
} finally {
btn.disabled = false;
btn.textContent = 'Export All Platforms';
}
}
/**
* Setup event listeners
*/
function setupEventListeners() {
document.getElementById('export-all-btn').addEventListener('click', exportAllCookies);
document.getElementById('settings-btn').addEventListener('click', () => {
browser.runtime.openOptionsPage();
});
}
/**
* Show success message
* @param {string} message - Message to display
*/
function showSuccess(message) {
showStatusMessage(message, 'success');
}
/**
* Show error message
* @param {string} message - Message to display
*/
function showError(message) {
showStatusMessage(message, 'error');
}
/**
* Show warning message
* @param {string} message - Message to display
*/
function showWarning(message) {
showStatusMessage(message, 'warning');
}
/**
* Show a status message
* @param {string} message - Message text
* @param {string} type - Message type (success, error, warning)
*/
function showStatusMessage(message, type) {
const el = document.getElementById('status-message');
el.textContent = message;
el.className = `status-message ${type}`;
el.classList.remove('hidden');
}
/**
* Hide the status message
*/
function hideStatusMessage() {
document.getElementById('status-message').classList.add('hidden');
}