diff --git a/background.js b/background.js index a89f998..48f2e28 100644 --- a/background.js +++ b/background.js @@ -3,11 +3,10 @@ // cookieStoreIds of all managed containers let containerCleanupTimer = null; let opennewtab = false; -let usecolors = []; let deldelay = 3000; let multiopen = 3; -//let highlightedTabs = new Map(); // ids - +let mode = null; +let regexList = null; // array of all allowed container colors const allcolors = [ "blue", @@ -19,6 +18,52 @@ const allcolors = [ "pink", "purple", ]; +let usecolors = []; +let historyPermission = { + permissions: ["history"], +}; + +function isOnRegexList(url) { + for (let i = 0; i < regexList.length; i++) { + if (regexList[i].test(url)) { + return true; + } + } + return false; +} + +async function buildRegExList() { + let selectors = await getFromStorage("object", "selectors", []); + + const out = []; + + selectors.forEach((e) => { + // check activ + if (typeof e.activ !== "boolean") { + return; + } + if (e.activ !== true) { + return; + } + + // check url regex + if (typeof e.url_regex !== "string") { + return; + } + e.url_regex = e.url_regex.trim(); + if (e.url_regex === "") { + return; + } + + try { + out.push(new RegExp(e.url_regex)); + } catch (e) { + return; + } + }); + + return out; +} async function getFromStorage(type, id, fallback) { let tmp = await browser.storage.local.get(id); @@ -108,7 +153,7 @@ async function createTempContainerTab(url, activ = true) { let tabs = await browser.tabs.query({ currentWindow: true, active: true }); const index = tabs.length > 0 ? tabs[0].index + 1 : -1; - obj = { + let obj = { active: activ, index: index, cookieStoreId: container.cookieStoreId, @@ -150,7 +195,7 @@ async function createContainer() { return container; } -async function syncMemory() { +async function onStorageChange() { opennewtab = await getFromStorage("boolean", "opennewtab", false); usecolors = await getFromStorage("object", "usecolors", allcolors); if (!Array.isArray(usecolors)) { @@ -161,19 +206,56 @@ async function syncMemory() { } deldelay = await getFromStorage("number", "deldelay", 3000); multiopen = await getFromStorage("number", "multiopen", 3); + + mode = !(await getFromStorage("boolean", "mode", false)); + regexList = await buildRegExList(); } -(async () => { - await syncMemory(); - setTimeout(onTabRemoved, deldelay); -})(); +async function onTabUpdated(tabId, changeInfo, tabInfo) { + if (typeof changeInfo.url === "string") { + if (changeInfo.url.startsWith("http")) { + try { + const container = await browser.contextualIdentities.get( + tabInfo.cookieStoreId + ); + //if (container !== null) { // spec error, doenst work because an error is thrown + // in a container + if (container.name.startsWith("Temp")) { + // delete history? + if (await browser.permissions.contains(historyPermission)) { + const visits = await browser.history.getVisits({ + url: changeInfo.url, + }); + if (visits.length < 5) { + setTimeout(() => { + browser.history.deleteUrl({ + url: changeInfo.url, + }); + }, 2000); + } + } + } + } catch (e) { + //} else { + // not in a container + const _isOnList = isOnRegexList(changeInfo.url); + if ((!mode && !_isOnList) || (mode && _isOnList)) { + createTempContainerTab(changeInfo.url, true); + browser.tabs.remove(tabId); + } + } + } + } +} -// register listeners -browser.tabs.onRemoved.addListener(onTabRemoved); -browser.browserAction.onClicked.addListener(onBAClicked); -browser.storage.onChanged.addListener(syncMemory); +// show the user the options page on first installation +function onInstall(details) { + if (details.reason === "install") { + browser.runtime.openOptionsPage(); + } +} -browser.commands.onCommand.addListener(async (command) => { +async function onCommand(command) { if (command === "opennewtab") { createTempContainerTab("about:newtab"); } @@ -197,62 +279,21 @@ browser.commands.onCommand.addListener(async (command) => { } } } -}); - -async function handleUpdated(tabId, changeInfo, tabInfo) { - if (changeInfo.url) { - if (changeInfo.url.startsWith("http")) { - try { - const container = await browser.contextualIdentities.get( - tabInfo.cookieStoreId - ); - if (container.name.startsWith("Temp")) { - const visits = await browser.history.getVisits({ - url: changeInfo.url, - }); - - if (visits.length < 5) { - setTimeout(() => { - browser.history.deleteUrl({ - url: changeInfo.url, - }); - }, 2000); - } - } - } catch (e) { - // noop - } - } - } -} - -var testPermissions1 = { - permissions: ["history"], -}; - -// register listener depending on available permissions -async function handlePermissionChange(permissions) { - if (await browser.permissions.contains(testPermissions1)) { - await browser.tabs.onUpdated.addListener(handleUpdated); - } else { - await browser.tabs.onUpdated.removeListener(handleUpdated); - } } -function handleHighlighted(highlightInfo) { - highlightedTabs.set(highlightInfo.windowId, highlightInfo.tabIds); -} +(async () => { + browser.runtime.onInstalled.addListener(onInstall); // needs to be first -// show the user the options page on first installation -function handleInstalled(details) { - if (details.reason === "install") { - browser.runtime.openOptionsPage(); - } -} + // init vars + await onStorageChange(); -browser.runtime.onInstalled.addListener(handleInstalled); + // trigger inital cleanup, for browser restart + setTimeout(onTabRemoved, deldelay); -// history related -browser.permissions.onRemoved.addListener(handlePermissionChange); -browser.permissions.onAdded.addListener(handlePermissionChange); -handlePermissionChange(); + // register listeners + browser.browserAction.onClicked.addListener(onBAClicked); + browser.commands.onCommand.addListener(onCommand); + browser.storage.onChanged.addListener(onStorageChange); + browser.tabs.onRemoved.addListener(onTabRemoved); + browser.tabs.onUpdated.addListener(onTabUpdated); +})(); diff --git a/manifest.json b/manifest.json index c2b36a1..a2f43bb 100644 --- a/manifest.json +++ b/manifest.json @@ -34,5 +34,5 @@ "tabs" ], "optional_permissions": ["bookmarks", "history"], - "version": "1.1.17" + "version": "1.1.18" } diff --git a/options.html b/options.html index 9facefb..b1be4cc 100644 --- a/options.html +++ b/options.html @@ -57,5 +57,51 @@ +
+ + + + + Mode: +

RegEx-URL-Matchers

+ + + + + + + +
+
+ diff --git a/options.js b/options.js index d6dce49..abe85f8 100644 --- a/options.js +++ b/options.js @@ -7,7 +7,7 @@ function onChange(evt) { let value = el.type === "checkbox" ? el.checked : el.value; let obj = {}; - console.log(id, value, el.type); + //console.log(id, value, el.type); if (value === "") { return; } @@ -30,7 +30,7 @@ function onChange(evt) { browser.storage.local.set(obj).catch(console.error); } -["multiopen", "deldelay", "opennewtab"].map((id) => { +["mode", "multiopen", "deldelay", "opennewtab"].map((id) => { browser.storage.local .get(id) .then((obj) => { @@ -71,9 +71,157 @@ function onChange(evt) { const selectedItems = Array.from(el.selectedOptions).map( (option) => option.value ); - console.debug(selectedItems); + //console.debug(selectedItems); let obj = {}; obj[id] = selectedItems; browser.storage.local.set(obj).catch(console.error); }); }); + +function deleteRow(rowTr) { + mainTableBody.removeChild(rowTr); +} + +function createTableRow(feed) { + var tr = mainTableBody.insertRow(); + var input; + + Object.keys(feed) + .sort() + .forEach((key) => { + if (key === "activ") { + input = document.createElement("input"); + input.className = key; + input.placeholder = key; + input.style.width = "100%"; + input.type = "checkbox"; + input.checked = typeof feed[key] === "boolean" ? feed[key] : true; + tr.insertCell().appendChild(input); + } else if (key !== "action") { + input = document.createElement("input"); + input.className = key; + input.placeholder = key; + input.style.width = "100%"; + input.value = feed[key]; + tr.insertCell().appendChild(input); + } + }); + + var button; + if (feed.action === "save") { + button = createButton("Save", "saveButton", function () {}, true); + } else { + button = createButton( + "Delete", + "deleteButton", + function () { + deleteRow(tr); + }, + false + ); + } + tr.insertCell().appendChild(button); +} + +function collectConfig() { + var feeds = []; + for (var row = 0; row < mainTableBody.rows.length; row++) { + try { + var url_regex = mainTableBody.rows[row] + .querySelector(".url_regex") + .value.trim(); + var check = mainTableBody.rows[row].querySelector(".activ").checked; + if (url_regex !== "") { + feeds.push({ + activ: check, + url_regex: url_regex, + }); + } + } catch (e) { + console.error(e); + } + } + return feeds; +} + +function createButton(text, id, callback, submit) { + var span = document.createElement("span"); + var button = document.createElement("button"); + button.id = id; + button.textContent = text; + button.className = "browser-style"; + if (submit) { + button.type = "submit"; + } else { + button.type = "button"; + } + button.name = id; + button.value = id; + button.addEventListener("click", callback); + span.appendChild(button); + return span; +} + +async function saveOptions(/*e*/) { + var config = collectConfig(); + await browser.storage.local.set({ selectors: config }); +} + +async function restoreOptions() { + createTableRow({ + activ: 1, + url_regex: "", + action: "save", + }); + var res = await browser.storage.local.get("selectors"); + if (!Array.isArray(res.selectors)) { + return; + } + res.selectors.forEach((selector) => { + selector.action = "delete"; + createTableRow(selector); + }); +} + +document.addEventListener("DOMContentLoaded", restoreOptions); +document.querySelector("form").addEventListener("submit", saveOptions); + +const impbtnWrp = document.getElementById("impbtn_wrapper"); +const impbtn = document.getElementById("impbtn"); +const expbtn = document.getElementById("expbtn"); + +expbtn.addEventListener("click", async function () { + var dl = document.createElement("a"); + var res = await browser.storage.local.get("selectors"); + var content = JSON.stringify(res.selectors); + dl.setAttribute( + "href", + "data:application/json;charset=utf-8," + encodeURIComponent(content) + ); + dl.setAttribute("download", "data.json"); + dl.setAttribute("visibility", "hidden"); + dl.setAttribute("display", "none"); + document.body.appendChild(dl); + dl.click(); + document.body.removeChild(dl); +}); + +// delegate to real Import Button which is a file selector +impbtnWrp.addEventListener("click", function () { + impbtn.click(); +}); + +impbtn.addEventListener("input", function () { + var file = this.files[0]; + var reader = new FileReader(); + reader.onload = async function () { + try { + var config = JSON.parse(reader.result); + await browser.storage.local.set({ selectors: config }); + document.querySelector("form").submit(); + } catch (e) { + console.error("error loading file: " + e); + } + }; + reader.readAsText(file); +});