From 0c9f5fefdae34da59aed5b842350779c9a440c52 Mon Sep 17 00:00:00 2001 From: eyedeekay Date: Tue, 14 Jan 2025 15:30:04 -0500 Subject: [PATCH] refactor bookmarks.js --- bookmarks.js | 314 +++++++++++++++++++++++++++++++-------------------- context.js | 71 ++++++------ 2 files changed, 227 insertions(+), 158 deletions(-) diff --git a/bookmarks.js b/bookmarks.js index 3c63966..57549d0 100644 --- a/bookmarks.js +++ b/bookmarks.js @@ -1,142 +1,210 @@ -async function createI2PToolbar(bookmarkToolbar) { - const ibbt = await browser.bookmarks.search("I2P Toolbar"); +/** + * @fileoverview I2P Bookmark Manager + * Handles bookmark creation and management for I2P extension toolbar + */ - async function onToolbarCreated(node) { - const ibt = await browser.bookmarks.search("I2P Toolbar"); - await bookmarks(ibt[0]); - } - - async function setupDir(ibbt) { - if (!ibbt.length) { - const createBookmark = await browser.bookmarks.create({ - title: "I2P Toolbar", - parentId: bookmarkToolbar.id, - }); - await onToolbarCreated(createBookmark); - } - } - - await setupDir(ibbt); -} - -async function bookmarks(bookmarkToolbar) { - const controlHost = control_host(); - const controlPort = control_port(); - - async function createBookmark({ url, title, parentId }) { - const createRhizomeBookmark = await browser.bookmarks.create({ - url, - title, - parentId, - }); - console.log("Bookmarked", createRhizomeBookmark); - } - - async function createHomeBookmark() { - const bookmarkItems = await browser.bookmarks.search({ +// Constants for bookmark configuration +const BOOKMARK_CONFIG = { + TOOLBAR_NAME: "I2P Toolbar", + DEFAULT_BOOKMARKS: [ + { title: "I2P Extension Home Page", - }); - if (!bookmarkItems.length) { - await createBookmark({ - url: browser.runtime.getURL("home.html"), - title: "I2P Extension Home Page", - parentId: bookmarkToolbar.id, - }); - } - } - - async function createTorrentBookmark() { - const bookmarkItems = await browser.bookmarks.search({ + getUrl: () => browser.runtime.getURL("home.html"), + }, + { title: "Bittorrent", - }); - if (!bookmarkItems.length) { - await createBookmark({ - url: `http://${controlHost}:${controlPort}/i2psnark`, - title: "Bittorrent", - parentId: bookmarkToolbar.id, - }); - } - } - - async function createConsoleBookmark() { - const bookmarkItems = await browser.bookmarks.search({ - title: "I2P Console", - }); - if (!bookmarkItems.length) { - await createBookmark({ - url: `http://${controlHost}:${controlPort}/home`, - title: "I2P Console", - parentId: bookmarkToolbar.id, - }); - } - } - - async function createMailBookmark() { - const bookmarkItems = await browser.bookmarks.search({ - title: "Web Mail", - }); - if (!bookmarkItems.length) { - await createBookmark({ - url: `http://${controlHost}:${controlPort}/webmail`, - title: "Web Mail", - parentId: bookmarkToolbar.id, - }); - } - } - - async function createI2PTunnelBookmark() { - const bookmarkItems = await browser.bookmarks.search({ + getUrl: (host, port) => `http://${host}:${port}/i2psnark`, + }, + { title: "Hidden Services Manager", - }); - if (!bookmarkItems.length) { - await createBookmark({ - url: `http://${controlHost}:${controlPort}/i2ptunnel`, - title: "Hidden Services Manager", - parentId: bookmarkToolbar.id, - }); + getUrl: (host, port) => `http://${host}:${port}/i2ptunnel`, + }, + { + title: "Web Mail", + getUrl: (host, port) => `http://${host}:${port}/webmail`, + }, + { + title: "I2P Console", + getUrl: (host, port) => `http://${host}:${port}/home`, + }, + ], +}; + +/** + * Bookmark Manager class for handling I2P bookmarks + */ +class I2PBookmarkManager { + constructor() { + this.controlHost = control_host(); + this.controlPort = control_port(); + } + + /** + * Creates a bookmark with error handling + * @param {Object} params Bookmark parameters + * @return {Promise} + */ + async createBookmark({ url, title, parentId }) { + try { + const bookmark = await browser.bookmarks.create({ url, title, parentId }); + console.info("Created bookmark:", title); + return bookmark; + } catch (error) { + console.error(`Failed to create bookmark ${title} :`, error); + throw error; } } - await createHomeBookmark(); - await createTorrentBookmark(); - await createI2PTunnelBookmark(); - await createMailBookmark(); - await createConsoleBookmark(); + /** + * Creates the I2P toolbar folder + * @param {browser.bookmarks.BookmarkTreeNode} toolbar Parent toolbar node + * @return {Promise} + */ + async createToolbarFolder(toolbar) { + try { + const existing = await browser.bookmarks.search( + BOOKMARK_CONFIG.TOOLBAR_NAME + ); + if (existing.length) { + return existing[0]; + } - defaultSettings.bookmarks_state = true; + const folder = await this.createBookmark({ + title: BOOKMARK_CONFIG.TOOLBAR_NAME, + parentId: toolbar.id, + }); + + await this.populateToolbar(folder); + return folder; + } catch (error) { + console.error("Failed to create toolbar folder:", error); + throw error; + } + } + + /** + * Creates a single default bookmark if it doesn't exist + * @param {Object} bookmark Bookmark configuration + * @param {string} parentId Parent folder ID + */ + async createDefaultBookmark(bookmark, parentId) { + try { + const existing = await browser.bookmarks.search({ + title: bookmark.title, + }); + if (!existing.length) { + await this.createBookmark({ + url: bookmark.getUrl(this.controlHost, this.controlPort), + title: bookmark.title, + parentId, + }); + } + } catch (error) { + console.error( + `Failed to create default bookmark ${bookmark.title}:`, + error + ); + } + } + + /** + * Populates toolbar with default bookmarks + * @param {browser.bookmarks.BookmarkTreeNode} toolbar Toolbar folder node + */ + async populateToolbar(toolbar) { + try { + await Promise.all( + BOOKMARK_CONFIG.DEFAULT_BOOKMARKS.map((bookmark) => + this.createDefaultBookmark(bookmark, toolbar.id) + ) + ); + await this.updateBookmarkState(true); + } catch (error) { + console.error("Failed to populate toolbar:", error); + } + } + + /** + * Updates bookmark state in storage + * @param {boolean} state New bookmark state + */ + async updateBookmarkState(state) { + try { + await browser.storage.local.set({ bookmarks_state: state }); + if (typeof defaultSettings !== "undefined") { + defaultSettings.bookmarks_state = state; + } + } catch (error) { + console.error("Failed to update bookmark state:", error); + } + } + + /** + * Initializes bookmark setup + * @returns {Promise} + */ + async initialize() { + try { + const platform = await browser.runtime.getPlatformInfo(); + if (platform.os === "android") { + console.info("Skipping bookmark setup on Android"); + return; + } + + const toolbars = await browser.bookmarks.search({ query: "Toolbar" }); + if (!toolbars.length) { + throw new Error("Browser toolbar not found"); + } + + await this.createToolbarFolder(toolbars[0]); + } catch (error) { + console.error("Bookmark initialization failed:", error); + } + } + + /** + * Checks if bookmarks need to be initialized + * @param {Object} state Current bookmark state + */ + async checkInitialization(state = {}) { + if (!state.bookmarks_state) { + await this.initialize(); + } + } } -async function bookmarksSetup() { - const gettingInfo = await browser.runtime.getPlatformInfo(); - if (gettingInfo.os === "android") { +// Singleton instance +const bookmarkManager = new I2PBookmarkManager(); + +/** + * Initialize bookmarks system + */ +async function initializeBookmarks() { + if (!browser?.windows) { + console.warn("Browser windows API not available"); return; } - const bookmarkToolbar = await browser.bookmarks.search({ - query: "Toolbar", - }); - - await createI2PToolbar(bookmarkToolbar[0]); -} - -function conditionalBookmarksSetup(obj) { - console.log("(bookmarks) state", obj.bookmarks_state); - if (obj.bookmarks_state == false) { - bookmarksSetup(); - } - if (obj.bookmarks_state == undefined) { - bookmarksSetup(); + try { + const state = await browser.storage.local.get("bookmarks_state"); + await bookmarkManager.checkInitialization(state); + } catch (error) { + console.error("Failed to initialize bookmarks:", error); + await bookmarkManager.initialize(); } } -if (browser != null) { - if (browser.windows != undefined) { - let gettingStorage = browser.storage.local.get("bookmarks_state"); - gettingStorage.then(conditionalBookmarksSetup, bookmarksSetup); +// Setup event listeners +document.addEventListener("DOMContentLoaded", () => { + const bookmarksButton = document.getElementById("bookmarksButton"); + if (bookmarksButton) { + bookmarksButton.addEventListener("click", () => + bookmarkManager.initialize() + ); } -} +}); -const bookmarksButton = document.getElementById("bookmarksButton"); -if (bookmarksButton != null) { - bookmarksButton.addEventListener("click", bookmarksSetup); +// Initialize if browser API is available +if (browser) { + initializeBookmarks(); } diff --git a/context.js b/context.js index 1abacf7..08131d4 100644 --- a/context.js +++ b/context.js @@ -5,25 +5,26 @@ // Constants const UI_STRINGS = { - TITLE_PREFACE: chrome.i18n.getMessage('titlePreface'), - API_ERROR_MESSAGE: 'browser.contextualIdentities not available. Check that the privacy.userContext.enabled pref is set to true, and reload the add-on.', - NO_IDENTITIES_MESSAGE: 'No identities returned from the API.' + TITLE_PREFACE: chrome.i18n.getMessage("titlePreface"), + API_ERROR_MESSAGE: + "browser.contextualIdentities not available. Check that the privacy.userContext.enabled pref is set to true, and reload the add-on.", + NO_IDENTITIES_MESSAGE: "No identities returned from the API.", }; const TAB_ACTIONS = { - NEW_TAB: 'new-i2p browser tab', - CLOSE_ALL: 'close-all i2p browser tabs' + NEW_TAB: "new-i2p browser tab", + CLOSE_ALL: "close-all i2p browser tabs", }; const TAB_OPTIONS = [ { - text: 'New I2P Browser Tab', - action: TAB_ACTIONS.NEW_TAB + text: "New I2P Browser Tab", + action: TAB_ACTIONS.NEW_TAB, }, { - text: 'Close All I2P Browser Tabs', - action: TAB_ACTIONS.CLOSE_ALL - } + text: "Close All I2P Browser Tabs", + action: TAB_ACTIONS.CLOSE_ALL, + }, ]; /** @@ -31,7 +32,7 @@ const TAB_OPTIONS = [ * @param {Error} error - Browser operation error */ function handleError(error) { - console.error('Container operation failed:', error); + console.error("Container operation failed:", error); } /** @@ -43,10 +44,10 @@ async function createContainerTab(windowInfo, cookieStoreId) { try { await browser.tabs.create({ windowId: windowInfo.id, - url: 'about:blank', - cookieStoreId: cookieStoreId + url: "about:blank", + cookieStoreId: cookieStoreId, }); - console.info(`Created container tab in window: ${windowInfo.id}`); + console.info(`Created container tab in window : ${windowInfo.id}`); } catch (error) { handleError(error); } @@ -69,11 +70,11 @@ async function handleContainerAction(event) { case TAB_ACTIONS.CLOSE_ALL: const tabs = await browser.tabs.query({ cookieStoreId: identity }); - await browser.tabs.remove(tabs.map(tab => tab.id)); + await browser.tabs.remove(tabs.map((tab) => tab.id)); break; default: - console.warn('Unknown container action:', action); + console.warn("Unknown container action:", action); } } catch (error) { handleError(error); @@ -86,18 +87,18 @@ async function handleContainerAction(event) { * @param {Object} identity - Container identity */ function createContainerOptions(parentNode, identity) { - TAB_OPTIONS.forEach(option => { - const link = document.createElement('a'); + TAB_OPTIONS.forEach((option) => { + const link = document.createElement("a"); Object.assign(link, { - href: '#', + href: "#", innerText: option.text, dataset: { action: option.action, - identity: identity.cookieStoreId - } + identity: identity.cookieStoreId, + }, }); - - link.addEventListener('click', handleContainerAction); + + link.addEventListener("click", handleContainerAction); parentNode.appendChild(link); }); } @@ -108,15 +109,15 @@ function createContainerOptions(parentNode, identity) { * @returns {HTMLElement} */ function createIdentityElement(identity) { - const row = document.createElement('div'); - const span = document.createElement('div'); - - span.className = 'identity'; + const row = document.createElement("div"); + const span = document.createElement("div"); + + span.className = "identity"; span.innerText = identity.name; - + row.appendChild(span); createContainerOptions(row, identity); - + return row; } @@ -132,7 +133,7 @@ async function initializeContainerUI(containerList) { try { const identities = await browser.contextualIdentities.query({ - name: UI_STRINGS.TITLE_PREFACE + name: UI_STRINGS.TITLE_PREFACE, }); if (!identities.length) { @@ -140,10 +141,10 @@ async function initializeContainerUI(containerList) { return; } - identities.forEach(identity => { + identities.forEach((identity) => { const element = createIdentityElement(identity); containerList.appendChild(element); - console.debug('Added container identity:', identity.name); + console.debug("Added container identity:", identity.name); }); } catch (error) { handleError(error); @@ -152,9 +153,9 @@ async function initializeContainerUI(containerList) { } // Initialize container management -const identityList = document.getElementById('identity-list'); +const identityList = document.getElementById("identity-list"); if (identityList) { initializeContainerUI(identityList); } else { - console.error('Identity list container not found'); -} \ No newline at end of file + console.error("Identity list container not found"); +}