diff --git a/config/util.js b/config/util.js new file mode 100644 index 0000000..8d40db2 --- /dev/null +++ b/config/util.js @@ -0,0 +1,5 @@ + + +module.exports = { + backgroundFiles: ['background.js', 'service-worker.js', 'manifest.json'] +} diff --git a/package-lock.json b/package-lock.json index 17f3786..b9b1b00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "react-boilerplate", - "version": "0.1.0", + "name": "window-saver", + "version": "1.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -9108,6 +9108,11 @@ } } }, + "node-watch": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", + "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==" + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", diff --git a/package.json b/package.json index 468d61d..f0d13d9 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "jest-watch-typeahead": "0.4.2", "lodash": "^4.17.19", "mini-css-extract-plugin": "0.9.0", + "node-watch": "^0.7.3", "optimize-css-assets-webpack-plugin": "5.0.3", "pnp-webpack-plugin": "1.6.4", "postcss-flexbugs-fixes": "4.1.0", @@ -70,11 +71,12 @@ "scripts": { "start": "node scripts/start.js", "watch": "node scripts/watch.js", + "watch:background": "node scripts/watchBackground.js", "watch:options": "node scripts/watchOptions.js", "build:popup": "node scripts/build.js", "build:options": "node scripts/buildOptions.js", - "build": "rm -rf build/ && npm run build:popup && npm run build:options", - "build:bg": "cp src/background/index.js build/background.js", + "build:background": "node scripts/buildBackground.js", + "build": "rm -rf build/ && npm run build:popup && npm run build:options && npm run build:background", "copy": "node scripts/copy.js", "test": "node scripts/test.js" }, diff --git a/public/background.js b/public/background.js deleted file mode 100644 index 2bbf789..0000000 --- a/public/background.js +++ /dev/null @@ -1,56 +0,0 @@ -browserMod.runtime.onInstalled.addListener(init) -browserMod.runtime.onMessage.addListener(handleMessage) -const defaultSettings = { - confirmSavePrivate: true, - confirmDelete: true, - confirmOverride: true, - confirmReplaceNonPrivate: false, - confirmReplacePrivate: false, - showHints: true, -} -async function init() { - const response = await browserMod.storage.local.get('settings') - if (response && response['settings']) { - return - } - browserMod.storage.local.set({ settings: defaultSettings }) -} -async function handleMessage(request) { - if (request.task === 'open_separate' || request.task === 'open_same') { - let currentWindow = await browserMod.windows.getCurrent() - let tabList = request.data - let windowInfo = await browserMod.windows.create() - let errors = [] - let length = tabList.length - for (var i = 0; i < length; i++) { - let tab = tabList[i] - try { - if ( - typeof browser !== 'undefined' && - Object.getPrototypeOf(browser) === Object.prototype - ) { - await browserMod.tabs.create({ - active: false, - discarded: true, - title: tab.title, - url: tab.url, - windowId: windowInfo.id, - }) - } else { - await browserMod.tabs.create({ - active: false, - url: tab.url, - windowId: windowInfo.id, - }) - } - } catch (err) { - errors.push(tab) - } - } - let response = await browserMod.tabs.query({ windowId: windowInfo.id }) - await browserMod.tabs.move(response[0]['id'], { index: -1 }) - console.log('<==== Following tabs could not be opened ====>') - console.log(errors) - request.task === 'open_same' && browserMod.windows.remove(currentWindow.id) - } -} diff --git a/public/firefox-manifest.json b/public/firefox-manifest.json new file mode 100644 index 0000000..fa53d97 --- /dev/null +++ b/public/firefox-manifest.json @@ -0,0 +1,49 @@ +{ + "manifest_version": 2, + "name": "Window Saver", + "description": "Save Windows to visit them later.", + "version": "1.8", + "icons":{ + "48": "icons/dark.png", + "96": "icons/dark.png" + }, + "browser_action":{ + "default_title": "Window Saver", + "default_popup": "index.html", + "default_icon": { + "16": "icons/dark.png", + "32": "icons/dark.png", + "64": "icons/dark.png", + "128": "icons/dark.png" + }, + "theme_icons": [ + { + "size": 16, + "light": "icons/light.png", + "dark": "icons/dark.png" + }, { + "size": 32, + "light": "icons/light.png", + "dark": "icons/dark.png" + }, { + "size": 64, + "light": "icons/light.png", + "dark": "icons/dark.png" + }, { + "size": 128, + "light": "icons/light.png", + "dark": "icons/dark.png" + } + ] + }, + "options_ui": { + "page": "options.html" + }, + "permissions": [ + "tabs", + "storage" + ], + "background": { + "scripts": ["browser-polyfill.js","background.js"] + } +} diff --git a/scripts/buildBackground.js b/scripts/buildBackground.js new file mode 100644 index 0000000..75b4449 --- /dev/null +++ b/scripts/buildBackground.js @@ -0,0 +1,15 @@ +const fs = require('fs-extra') +const paths = require('../config/paths') +const utilConfig = require('../config/util') + + + +function copyBackgroundScripts() { + console.log("<==== copying background scripts ====>") + utilConfig.backgroundFiles.forEach((filename) => { + console.log(" copying %s ...", filename) + fs.copyFile(paths.appSrc + '/background/' + filename, paths.appBuild + '/' + filename) + }) +} + +copyBackgroundScripts() diff --git a/scripts/watchBackground.js b/scripts/watchBackground.js new file mode 100644 index 0000000..5086058 --- /dev/null +++ b/scripts/watchBackground.js @@ -0,0 +1,17 @@ +const fs = require('fs-extra') +const path = require('path') +const watch = require('node-watch'); + +const paths = require('../config/paths') +const utilConfig = require('../config/util') + +watch(paths.appSrc + '/background/', function(evt, name) { + if(name) { + const basename = path.basename(name) + console.log("<==== changes registered in file %s ====>", basename) + if (utilConfig.backgroundFiles.includes(basename)) { + console.log(" updating build folder ... \n") + fs.copyFile(name, paths.appBuild + '/' + basename) + } + } +}); diff --git a/src/background/background.js b/src/background/background.js new file mode 100644 index 0000000..de822db --- /dev/null +++ b/src/background/background.js @@ -0,0 +1,121 @@ +browserMod.runtime.onInstalled.addListener(init) +browserMod.runtime.onMessage.addListener(handleMessage) + +const defaultSettings = { + confirmSavePrivate: true, + confirmDelete: true, + confirmOverride: true, + confirmReplaceNonPrivate: false, + confirmReplacePrivate: false, + showHints: true, + updateStorage: true, +} + +async function init() { + try { + console.log('init called') + // let response = await browserMod.storage.sync.get('settings') + // let syncSettings = response?.settings + // console.log(syncSettings) + // if (!syncSettings) { + // // if not sync, check the local and convert to sync + // response = await browserMod.storage.local.get('settings') + // let localSettings = response?.settings + // console.log(localSettings) + // if (localSettings) { + // response = await browserMod.storage.local.get('list') + // let localList = response?.list + // console.log(localList) + // response = await browserMod.storage.sync.set({ + // list: localList, + // settings: localSettings, + // }) + // console.log(response) + // syncSettings = localSettings + // } + // } + + // if (syncSettings) { + // if (!(updateStorage in syncSettings) || syncSettings['updateStorage']) { + // await updateStorage() + // await browserMod.storage.sync.set({ + // settings: { ...syncSettings, updateStorage: false }, + // }) + // } + // return + // } + // await browserMod.storage.sync.set({ settings: defaultSettings }) + + let response = await browserMod.storage.local.get('settings') + let localSettings = response?.settings + + if (localSettings) { + if (!(updateStorage in localSettings) || localSettings['updateStorage']) { + await updateStorage() + await browserMod.storage.local.set({ + settings: { ...localSettings, updateStorage: false }, + }) + } + return + } + await browserMod.storage.local.set({ settings: defaultSettings }) + } catch (e) { + console.log(e) + } +} + +async function updateStorage() { + const response = await browserMod.storage.local.get('list') + const list = response['list'] + if (Array.isArray(list) && list.length) { + const newList = list.map(item => { + if (!item?.id) { + return { ...item, id: crypto.randomUUID() } + } + return item + }) + await browserMod.storage.local.set({ list: newList }) + } +} + +async function handleMessage(request) { + if (request.task === 'open_separate' || request.task === 'open_same') { + let currentWindow = await browserMod.windows.getCurrent() + let tabList = request.data + let windowInfo = await browserMod.windows.create() + let errors = [] + let length = tabList.length + for (var i = 0; i < length; i++) { + let tab = tabList[i] + try { + if ( + typeof browser !== 'undefined' && + Object.getPrototypeOf(browser) === Object.prototype + ) { + await browserMod.tabs.create({ + active: false, + discarded: true, + title: tab.title, + url: tab.url, + windowId: windowInfo.id, + }) + } else { + await browserMod.tabs.create({ + active: false, + url: tab.url, + windowId: windowInfo.id, + }) + } + } catch (err) { + errors.push(tab) + } + } + let response = await browserMod.tabs.query({ windowId: windowInfo.id }) + await browserMod.tabs.move(response[0]['id'], { index: -1 }) + if (errors.length > 0) { + console.error('<==== Following tabs could not be opened ====>') + console.error(errors) + } + request.task === 'open_same' && browserMod.windows.remove(currentWindow.id) + } +} diff --git a/src/background/index.js b/src/background/index.js deleted file mode 100644 index cd07b72..0000000 --- a/src/background/index.js +++ /dev/null @@ -1,45 +0,0 @@ -browser.runtime.onInstalled.addListener(init) -browser.runtime.onMessage.addListener(handleMessage) -const defaultSettings = { - confirmSavePrivate: true, - confirmDelete: true, - confirmOverride: true, - confirmReplaceNonPrivate: false, - confirmReplacePrivate: false, - showHints: true, -} -async function init() { - const response = await browser.storage.local.get('settings') - if (response && response['settings']) { - return - } - browser.storage.local.set({ settings: defaultSettings }) -} -async function handleMessage(request) { - if (request.task === 'open_separate' || request.task === 'open_same') { - let currentWindow = await browser.windows.getCurrent() - let tabList = request.data - let windowInfo = await browser.windows.create() - let errors = [] - let length = tabList.length - for (var i = 0; i < length; i++) { - let tab = tabList[i] - try { - await browser.tabs.create({ - active: false, - discarded: true, - title: tab.title, - url: tab.url, - windowId: windowInfo.id, - }) - } catch (err) { - errors.push(tab) - } - } - let response = await browser.tabs.query({ windowId: windowInfo.id }) - await browser.tabs.move(response[0]['id'], { index: -1 }) - console.log('<==== Following tabs could not be opened ====>') - console.log(errors) - request.task === 'open_same' && browser.windows.remove(currentWindow.id) - } -} diff --git a/public/manifest.json b/src/background/manifest.json similarity index 86% rename from public/manifest.json rename to src/background/manifest.json index 3700100..6410eca 100644 --- a/public/manifest.json +++ b/src/background/manifest.json @@ -1,13 +1,13 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "Window Saver", "description": "Save Windows to visit them later.", - "version": "1.8", + "version": "1.9", "icons":{ "48": "icons/dark.png", "96": "icons/dark.png" }, - "browser_action":{ + "action":{ "default_title": "Window Saver", "default_popup": "index.html", "default_icon": { @@ -36,15 +36,15 @@ } ] }, + "options_page": "options.html", "options_ui": { "page": "options.html" }, "permissions": [ - "bookmarks", "tabs", "storage" ], "background": { - "scripts": ["browser-polyfill.js","background.js"] + "service_worker": "service-worker.js" } } diff --git a/src/background/service-worker.js b/src/background/service-worker.js new file mode 100644 index 0000000..5870965 --- /dev/null +++ b/src/background/service-worker.js @@ -0,0 +1,5 @@ +try { + importScripts('browser-polyfill.js', 'background.js'); +} catch (e) { + console.log(e); +} diff --git a/src/index.js b/src/index.js index 5e2fc7f..a8dc7c6 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ import { Provider } from 'react-redux' import store from './js/store' import './styles/index.scss' import App from './js/components/App' -import * as serviceWorker from './serviceWorker' +// import * as serviceWorker from './serviceWorker' ReactDOM.render( @@ -16,4 +16,4 @@ ReactDOM.render( // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister() +// serviceWorker.unregister() diff --git a/src/js/components/App.js b/src/js/components/App.js index f3dc0f6..d5d336c 100644 --- a/src/js/components/App.js +++ b/src/js/components/App.js @@ -42,6 +42,7 @@ class App extends Component { createdAt: time, updatedAt: time, urls: tabList, + id: crypto.randomUUID() }) this.setState({ list }, this.saveLocalDebounce) } @@ -154,10 +155,15 @@ class App extends Component { } async handleOpenNew(index) { const { list } = this.state - browser.runtime.sendMessage({ - task: 'open_separate', - data: list[index]['urls'], - }) + try { + browser.runtime.sendMessage({ + task: 'open_separate', + data: list[index]['urls'], + }) + } catch (e) { + console.error(e) + } + } exportData() { const { list } = this.state @@ -212,7 +218,6 @@ class App extends Component { id="name-input" onChange={e => this.setState({ name: e.target.value })} onKeyDown={e => { - console.log('wait') if (!e.shiftKey && e.key === 'Enter') { e.preventDefault() this.handleSave()