├── .github └── workflows │ └── main.yml ├── LICENSE ├── README.md ├── background.js ├── icon.png ├── manifest.json ├── options.html └── options.js /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push but only when manifest.json (is changed) 8 | push: 9 | branches: [ main ] 10 | paths: 11 | 'manifest.json' 12 | 13 | # Allows to run this workflow manually 14 | workflow_dispatch: 15 | 16 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 17 | jobs: 18 | # This workflow contains a single job called "build" 19 | build: 20 | # The type of runner that the job will run on 21 | runs-on: ubuntu-latest 22 | 23 | # Steps represent a sequence of tasks that will be executed as part of the job 24 | steps: 25 | # Runs a set of commands using the runners shell 26 | - name: run build script 27 | env: 28 | ISSUER: ${{secrets.ISSUER}} 29 | SECRET: ${{secrets.SECRET}} 30 | run: curl 'https://raw.githubusercontent.com/igorlogius/meta-addon-builder/main/README' | sh 31 | 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 igorlogius 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://addons.mozilla.org/firefox/addon/load-background-tabs-on-select/) 2 | 3 | [Report a bug, make a suggestion or ask a question](https://github.com/igorlogius/igorlogius/issues/new/choose) 4 | 5 | https://github.com/igorlogius/load-background-tabs-on-select/assets/67047467/83c02d4c-5da8-453f-90f5-5ee2a5e8d60c 6 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | /* global browser */ 2 | 3 | async function getFromStorage(type, id, fallback) { 4 | let tmp = await browser.storage.local.get(id); 5 | return typeof tmp[id] === type ? tmp[id] : fallback; 6 | } 7 | 8 | async function setToStorage(id, value) { 9 | let obj = {}; 10 | obj[id] = value; 11 | return browser.storage.local.set(obj); 12 | } 13 | 14 | (async () => { 15 | const temporary = browser.runtime.id.endsWith("@temporary-addon"); // debugging? 16 | const manifest = browser.runtime.getManifest(); 17 | const extname = manifest.name; 18 | let manually_disabled = false; 19 | 20 | async function getMode() { 21 | return await getFromStorage("boolean", "mode", false); 22 | } 23 | 24 | async function getRegexList() { 25 | let out = []; 26 | let tmp = await getFromStorage("string", "matchers", ""); 27 | 28 | tmp.split("\n").forEach((line) => { 29 | line = line.trim(); 30 | if (line !== "") { 31 | try { 32 | line = new RegExp(line.trim()); 33 | out.push(line); 34 | } catch (e) { 35 | console.error(e); 36 | } 37 | } 38 | }); 39 | return out; 40 | } 41 | 42 | function matchesRegEx(url) { 43 | for (let i = 0; i < regexList.length; i++) { 44 | if (regexList[i].test(url)) { 45 | return true; 46 | } 47 | } 48 | return false; 49 | } 50 | 51 | async function onStorageChange(/*changes, area*/) { 52 | manually_disabled = await getFromStorage( 53 | "boolean", 54 | "manually_disabled", 55 | false, 56 | ); 57 | if (!manually_disabled) { 58 | // 59 | browser.browserAction.setBadgeText({ text: "on" }); 60 | browser.browserAction.setBadgeBackgroundColor({ 61 | color: [0, 115, 0, 115], 62 | }); 63 | } else { 64 | // 65 | browser.browserAction.setBadgeText({ text: "off" }); 66 | browser.browserAction.setBadgeBackgroundColor({ 67 | color: [115, 0, 0, 115], 68 | }); 69 | } 70 | mode = await getMode(); 71 | regexList = await getRegexList(); 72 | } 73 | 74 | await onStorageChange(); 75 | 76 | // ------------------------------- 77 | 78 | let wasActive = new Set(); 79 | 80 | browser.tabs.onUpdated.addListener( 81 | (tabId, changeInfo, tab) => { 82 | // ignore 83 | if ( 84 | !( 85 | tab.active || 86 | tab.hidden || 87 | tab.discarded || 88 | wasActive.has(tabId) || 89 | manually_disabled || 90 | !changeInfo.url.startsWith("http") 91 | ) 92 | ) { 93 | const mre = matchesRegEx(tab.url); 94 | 95 | if ( 96 | (mode && mre) || // blacklist(true) => matches are not allowed to load 97 | (!mode && !mre) // whitelist(false) => matches are allowed to load <=> no match => not allowed 98 | ) { 99 | browser.tabs.discard(tabId); 100 | // console.debug("discarded", tab.url); 101 | } 102 | } 103 | }, 104 | { properties: ["url"] }, 105 | ); 106 | 107 | browser.tabs.onActivated.addListener((activeInfo) => { 108 | if (!wasActive.has(activeInfo.tabId)) { 109 | wasActive.add(activeInfo.tabId); 110 | } 111 | }); 112 | 113 | browser.tabs.onRemoved.addListener((tabId) => { 114 | if (wasActive.has(tabId)) { 115 | wasActive.delete(tabId); 116 | } 117 | }); 118 | 119 | browser.storage.onChanged.addListener(onStorageChange); 120 | browser.browserAction.onClicked.addListener(() => { 121 | if (manually_disabled) { 122 | // 123 | manually_disabled = false; 124 | browser.browserAction.setBadgeText({ text: "on" }); 125 | browser.browserAction.setBadgeBackgroundColor({ 126 | color: [0, 115, 0, 115], 127 | }); 128 | } else { 129 | // 130 | manually_disabled = true; 131 | browser.browserAction.setBadgeText({ text: "off" }); 132 | browser.browserAction.setBadgeBackgroundColor({ 133 | color: [115, 0, 0, 115], 134 | }); 135 | } 136 | setToStorage("manually_disabled", manually_disabled); 137 | }); 138 | browser.browserAction.setTitle({ title: "Toggle tab background loading" }); 139 | })(); 140 | 141 | browser.runtime.onInstalled.addListener(async (details) => { 142 | if (details.reason === "install") { 143 | browser.runtime.openOptionsPage(); 144 | } else { 145 | // Migrate old data 146 | let tmp = await getFromStorage("object", "selectors", []); 147 | tmp = tmp.map((e) => e.url_regex).join("\n"); 148 | await setToStorage("matchers", tmp); 149 | } 150 | }); 151 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorlogius/load-background-tabs-on-select/9c8c1ab40276caee0264a82c824484d8b324c9df/icon.png -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "igorlogius", 3 | "homepage_url": "https://github.com/igorlogius/load-background-tabs-on-select", 4 | "description": "Prevents tabs which are opend in the background from loading until they have been manually activated once", 5 | "background": { 6 | "scripts": ["background.js"] 7 | }, 8 | "browser_action": { 9 | "default_area": "navbar" 10 | }, 11 | "icons": { 12 | "128": "icon.png" 13 | }, 14 | "manifest_version": 2, 15 | "name": "Load Background Tabs On Select", 16 | "options_ui": { 17 | "page": "options.html" 18 | }, 19 | "permissions": ["storage", "tabs"], 20 | "version": "1.2.12" 21 | } 22 | -------------------------------------------------------------------------------- /options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |