diff --git a/extension/background.js b/extension/background.js deleted file mode 100644 index 6f9b829..0000000 --- a/extension/background.js +++ /dev/null @@ -1,37 +0,0 @@ -function bookmarkAll(folderTitle) { - console.log("Creating new bookmarks in " + folderTitle); - // Create folder - chrome.bookmarks.create( - { - title: folderTitle, - url: null - }, - function(folder){ - if (folder == null) { - alert("Unable to create new folder " + folderTitle); - return; - } - // Loop over all windows and their tabs - chrome.windows.getAll( - { - populate: true - }, - function(windowList) { - for (var i = 0; i < windowList.length; i++) { - for (var j = 0; j < windowList[i].tabs.length; j++) { - var tab = windowList[i].tabs[j]; - // Bookmark the tab - chrome.bookmarks.create( - { - parentId : folder.id, - title : tab.title, - url : tab.url - } - ); - } - } - } - ); - } - ); -} diff --git a/extension/manifest.json b/extension/manifest.json index abd78db..a77e7b8 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,5 +1,5 @@ { - "manifest_version": 2, + "manifest_version": 3, "version": "4", "name": "Bookmark All", "author": "Andrew Sutherland", @@ -12,7 +12,10 @@ "128": "star_icons_128.png", "48": "star_icons_48.png" }, - "browser_action": { + "background": { + "service_worker": "service_worker.js" + }, + "action": { "default_icon": { "19": "star_icons_19.png", "38": "star_icons_38.png" @@ -20,9 +23,5 @@ "default_popup": "popup.html", "default_title": "Bookmark All" }, - "background": { - "scripts": [ - "background.js" - ] - } -} + "content_security_policy": {} +} \ No newline at end of file diff --git a/extension/script.js b/extension/script.js index 4f69129..b256869 100644 --- a/extension/script.js +++ b/extension/script.js @@ -1,25 +1,37 @@ function toShortISODateString(d) { - function pad(n) { - return n<10 ? '0'+n : n - } - return d.getFullYear()+'-' - + pad(d.getMonth()+1)+'-' - + pad(d.getDate()); + const pad = (n) => (n < 10 ? "0" + n : n); + return ( + d.getFullYear() + + "-" + + pad(d.getMonth() + 1) + + "-" + + pad(d.getDate()) + ); } -$(document).ready(function(){ - var folderTitle = toShortISODateString(new Date()); - // Set default value to current date - $('#folderName').val(folderTitle); - console.log("Set placeholder to " + folderTitle); - // Handle button click - $('form').submit(function(){ - // This seems the stupidest way to get the value - var folderName = $('#folderName').val(); - window.close(); - // Create bookmarks from background page - // I couldn't get it to work from here - // and there seemed to be a race condition with window.close() - chrome.extension.getBackgroundPage().bookmarkAll(folderName); - return false; + +$(function () { + const defaultTitle = toShortISODateString(new Date()); + $("#folderName").val(defaultTitle); + console.log("Default folder name:", defaultTitle); + + $("form").on("submit", function (e) { + e.preventDefault(); + + const folderTitle = $("#folderName").val().trim() || defaultTitle; + + chrome.runtime.sendMessage( + { type: "BOOKMARK_ALL", folderTitle }, + (res) => { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError); + } else if (!res?.ok) { + console.error(res?.error || "Unknown error"); + } else { + console.log(`Bookmarked ${res.count} tabs into folder ${folderTitle}`); + } + // Close AFTER we get a response to avoid the race + window.close(); + } + ); }); }); diff --git a/extension/service_worker.js b/extension/service_worker.js new file mode 100644 index 0000000..bff9d20 --- /dev/null +++ b/extension/service_worker.js @@ -0,0 +1,50 @@ +const p = { + bookmarksCreate: (data) => + new Promise((resolve, reject) => + chrome.bookmarks.create(data, (res) => + chrome.runtime.lastError ? reject(chrome.runtime.lastError) : resolve(res) + ) + ), + windowsGetAll: (opts) => + new Promise((resolve, reject) => + chrome.windows.getAll(opts, (res) => + chrome.runtime.lastError ? reject(chrome.runtime.lastError) : resolve(res) + ) + ) +}; + +async function bookmarkAll(folderTitle) { + console.log("Creating new bookmarks in", folderTitle); + + // Create the folder + const folder = await p.bookmarksCreate({ title: folderTitle }); + + // Get all windows & tabs + const windows = await p.windowsGetAll({ populate: true }); + + let count = 0; + for (const win of windows) { + for (const tab of win.tabs) { + // Skip chrome://, edge://, etc. + if (!tab.url || !/^https?:/i.test(tab.url)) continue; + + await p.bookmarksCreate({ + parentId: folder.id, + title: tab.title || tab.url, + url: tab.url + }); + count++; + } + } + return { folderId: folder.id, count }; +} + +// Message router +chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => { + if (msg?.type === "BOOKMARK_ALL") { + bookmarkAll(msg.folderTitle) + .then((result) => sendResponse({ ok: true, ...result })) + .catch((err) => sendResponse({ ok: false, error: String(err) })); + return true; // keep channel open for async + } +});