126 lines
3.7 KiB
JavaScript
126 lines
3.7 KiB
JavaScript
/**
|
||
* Container Bookmarks - Popup Script
|
||
*/
|
||
|
||
const STORAGE_KEY = 'bookmark_container_mappings';
|
||
|
||
// Container color palette (matches Firefox)
|
||
const CONTAINER_COLORS = {
|
||
'blue': '#37adff',
|
||
'turquoise': '#00c79a',
|
||
'green': '#51cd00',
|
||
'yellow': '#ffcb00',
|
||
'orange': '#ff9f00',
|
||
'red': '#ff613d',
|
||
'pink': '#ff4bda',
|
||
'purple': '#af51f5',
|
||
'toolbar': '#7c7c7d'
|
||
};
|
||
|
||
/**
|
||
* Get all bookmark-container mappings
|
||
*/
|
||
async function getMappings() {
|
||
const result = await browser.storage.local.get(STORAGE_KEY);
|
||
return result[STORAGE_KEY] || {};
|
||
}
|
||
|
||
/**
|
||
* Get all containers
|
||
*/
|
||
async function getContainers() {
|
||
try {
|
||
return await browser.contextualIdentities.query({});
|
||
} catch (error) {
|
||
console.error('Failed to get containers:', error);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Remove a mapping
|
||
*/
|
||
async function removeMapping(bookmarkId) {
|
||
const mappings = await getMappings();
|
||
delete mappings[bookmarkId];
|
||
await browser.storage.local.set({ [STORAGE_KEY]: mappings });
|
||
}
|
||
|
||
/**
|
||
* Render the mappings list
|
||
*/
|
||
async function renderMappings() {
|
||
const mappingsListEl = document.getElementById('mappings-list');
|
||
const statsEl = document.getElementById('stats');
|
||
|
||
const mappings = await getMappings();
|
||
const containers = await getContainers();
|
||
const containerMap = {};
|
||
containers.forEach(c => containerMap[c.cookieStoreId] = c);
|
||
|
||
const entries = Object.entries(mappings);
|
||
|
||
if (entries.length === 0) {
|
||
mappingsListEl.innerHTML = '<p class="empty">No container assignments yet.<br>Right-click a bookmark to get started!</p>';
|
||
statsEl.textContent = '0 bookmarks assigned';
|
||
return;
|
||
}
|
||
|
||
mappingsListEl.innerHTML = '';
|
||
|
||
for (const [bookmarkId, mapping] of entries) {
|
||
try {
|
||
const bookmarks = await browser.bookmarks.get(bookmarkId);
|
||
if (!bookmarks || bookmarks.length === 0) {
|
||
// Orphaned mapping, clean up
|
||
await removeMapping(bookmarkId);
|
||
continue;
|
||
}
|
||
|
||
const bookmark = bookmarks[0];
|
||
const container = containerMap[mapping.containerId];
|
||
const containerColor = container ? CONTAINER_COLORS[container.color] || '#7c7c7d' : '#7c7c7d';
|
||
const containerName = container ? container.name : mapping.containerName;
|
||
|
||
const item = document.createElement('div');
|
||
item.className = 'mapping-item';
|
||
item.innerHTML = `
|
||
<div class="container-indicator" style="background-color: ${containerColor}"></div>
|
||
<div class="mapping-info">
|
||
<span class="bookmark-title" title="${bookmark.title}">${truncate(bookmark.title, 30)}</span>
|
||
<span class="container-name">${containerName}</span>
|
||
</div>
|
||
<button class="remove-btn" data-bookmark-id="${bookmarkId}" title="Remove assignment">×</button>
|
||
`;
|
||
|
||
mappingsListEl.appendChild(item);
|
||
} catch (error) {
|
||
// Bookmark doesn't exist, clean up
|
||
await removeMapping(bookmarkId);
|
||
}
|
||
}
|
||
|
||
const validCount = mappingsListEl.children.length;
|
||
statsEl.textContent = `${validCount} bookmark${validCount !== 1 ? 's' : ''} assigned`;
|
||
|
||
// Add click handlers for remove buttons
|
||
document.querySelectorAll('.remove-btn').forEach(btn => {
|
||
btn.addEventListener('click', async (e) => {
|
||
const bookmarkId = e.target.dataset.bookmarkId;
|
||
await removeMapping(bookmarkId);
|
||
renderMappings();
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Truncate text with ellipsis
|
||
*/
|
||
function truncate(text, maxLength) {
|
||
if (text.length <= maxLength) return text;
|
||
return text.substring(0, maxLength - 1) + '…';
|
||
}
|
||
|
||
// Initialize
|
||
document.addEventListener('DOMContentLoaded', renderMappings);
|