├── .gitignore ├── LICENSE ├── README.md ├── getbanglist.js └── plugin ├── background.js ├── bang.js ├── banglist ├── bangs.json └── version.json ├── grant_permissions.js ├── icon.png ├── manifest.json ├── options.html ├── options.js ├── permissions_page.css ├── permissions_page.html ├── permissions_page.js ├── search_engine.js ├── shared_functions.js └── startpage.js /.gitignore: -------------------------------------------------------------------------------- 1 | plugin.zip 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 tt7753 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bang! 2 | 3 | A firefox extension which adds duckduckgo bangs to various search engines. 4 | 5 | Info on how to use: https://duckduckgo.com/bang 6 | 7 | All bangs supported by duckduckgo are supported here. 8 | 9 | Supports google, bing, ecosia and startpage. 10 | -------------------------------------------------------------------------------- /getbanglist.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const https = require('https') 3 | https://duckduckgo.com/bv1.js 4 | 5 | function getversion(){ 6 | const options = { 7 | hostname: 'duckduckgo.com', 8 | port: 443, 9 | path: '/bv1.js', 10 | method: 'GET' 11 | } 12 | let str = ""; 13 | let version = ""; 14 | callback = function(response){ 15 | response.on('data', function (chunk) { 16 | str += chunk; 17 | }); 18 | 19 | response.on('end', function () { 20 | version = str.match(/^\d+|\d+\b|\d+(?=\w)/g)[0]; 21 | console.log(version); 22 | getbangs(version); 23 | }); 24 | } 25 | const req = https.request(options, callback).end(); 26 | } 27 | 28 | getversion(); 29 | 30 | function getbangs(version) { 31 | let str = ""; 32 | const options = { 33 | hostname: 'duckduckgo.com', 34 | port: 443, 35 | path: '/bang.v'+version+'.js', 36 | method: 'GET' 37 | } 38 | callback = function(response){ 39 | response.on('data', function (chunk) { 40 | str += chunk; 41 | }); 42 | 43 | response.on('end', function () { 44 | let data = JSON.stringify(str); 45 | const fs = require('fs'); 46 | fs.writeFile('bangs.json', str, function (err) { 47 | if (err) return console.log(err); 48 | }); 49 | 50 | }); 51 | } 52 | 53 | const req = https.request(options, callback).end(); 54 | } 55 | -------------------------------------------------------------------------------- /plugin/background.js: -------------------------------------------------------------------------------- 1 | chrome.webRequest.onBeforeRequest.addListener( 2 | function(info) { 3 | console.log(info); 4 | var url_s = info.url; 5 | var url = new URL(url_s); 6 | //we dont want a bang to trigger bc qwant is giving us suggestions 7 | if(url_s.includes("qwant.com/v3/suggest")){ 8 | return; 9 | } 10 | var search = url.searchParams.get("q"); 11 | console.log(search); 12 | match(url, search, info.tabId); 13 | }, 14 | // filters 15 | { 16 | urls: [ 17 | "http://www.google.com/search*", 18 | "http://www.google.co.jp/search*", 19 | "http://www.google.co.uk/search*", 20 | "http://www.google.es/search*", 21 | "http://www.google.ca/search*", 22 | "http://www.google.de/search*", 23 | "http://www.google.it/search*", 24 | "http://www.google.fr/search*", 25 | "http://www.google.com.au/search*", 26 | "http://www.google.com.tw/search*", 27 | "http://www.google.nl/search*", 28 | "http://www.google.com.br/search*", 29 | "http://www.google.com.tr/search*", 30 | "http://www.google.be/search*", 31 | "http://www.google.com.gr/search*", 32 | "http://www.google.co.in/search*", 33 | "http://www.google.com.mx/search*", 34 | "http://www.google.dk/search*", 35 | "http://www.google.com.ar/search*", 36 | "http://www.google.ch/search*", 37 | "http://www.google.cl/search*", 38 | "http://www.google.at/search*", 39 | "http://www.google.co.kr/search*", 40 | "http://www.google.ie/search*", 41 | "http://www.google.com.co/search*", 42 | "http://www.google.pl/search*", 43 | "http://www.google.pt/search*", 44 | "http://www.google.com.pk/search*", 45 | "https://www.google.com/search*", 46 | "https://www.google.co.jp/search*", 47 | "https://www.google.co.uk/search*", 48 | "https://www.google.es/search*", 49 | "https://www.google.ca/search*", 50 | "https://www.google.de/search*", 51 | "https://www.google.it/search*", 52 | "https://www.google.fr/search*", 53 | "https://www.google.com.au/search*", 54 | "https://www.google.com.tw/search*", 55 | "https://www.google.nl/search*", 56 | "https://www.google.com.br/search*", 57 | "https://www.google.com.tr/search*", 58 | "https://www.google.be/search*", 59 | "https://www.google.com.gr/search*", 60 | "https://www.google.co.in/search*", 61 | "https://www.google.com.mx/search*", 62 | "https://www.google.dk/search*", 63 | "https://www.google.com.ar/search*", 64 | "https://www.google.ch/search*", 65 | "https://www.google.cl/search*", 66 | "https://www.google.at/search*", 67 | "https://www.google.co.kr/search*", 68 | "https://www.google.ie/search*", 69 | "https://www.google.com.co/search*", 70 | "https://www.google.pl/search*", 71 | "https://www.google.pt/search*", 72 | "https://www.google.com.pk/search*", 73 | "https://*.startpage.com/do/dsearch*", 74 | "https://*.startpage.com/do/metasearch.pl*", 75 | "https://www.bing.com/search*", 76 | "https://*.ecosia.org/search*", 77 | "https://*.qwant.com/*" 78 | ] 79 | }, 80 | // extraInfoSpec 81 | ["blocking"]); 82 | 83 | 84 | 85 | function match(url, search, tab_id) { 86 | console.log("matching..."); 87 | if(search != null){ 88 | contains_possible_bang(search, function(b, raw_search, BANG){ 89 | if(b){ 90 | bang({ 91 | srch: search, 92 | raw_srch: raw_search, 93 | rpl: false, 94 | bng: BANG 95 | }, tab_id); 96 | } 97 | }); 98 | } 99 | } 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /plugin/bang.js: -------------------------------------------------------------------------------- 1 | browser.storage.sync.set({ 2 | "banglist": "" 3 | }); 4 | 5 | browser.storage.local.get(['version'], function (result) { 6 | var manv = browser.runtime.getManifest().version; 7 | if (result.version == null || result.version < manv) { 8 | console.log("reset banglist"); 9 | 10 | browser.storage.local.set({ 11 | "banglist": "", 12 | "version": manv 13 | }); 14 | } 15 | 16 | }); 17 | 18 | browser.runtime.onMessage.addListener(function (request, sender) { 19 | bang(request, sender.tab.id); 20 | }); 21 | 22 | function bang(request, tab_id) { 23 | var search = request.srch; 24 | var raw_search = request.raw_srch; 25 | var replace = request.rpl; 26 | var bang = request.bng; 27 | bang = "!" + bang.substring(1); 28 | console.log(bang); 29 | var search_url = request.srch_url; 30 | if (search == null) { return;} 31 | browser.storage.sync.get(['bangs', 'onlycustom', "useddg"], function (result) { 32 | var bangs = null; 33 | if (result.bangs != null) { 34 | bangs = JSON.parse(result.bangs); 35 | } 36 | 37 | //check custom bang 38 | if (bangs != null && bangs.length != 0) { 39 | for (let i = 0; i < bangs.length; i++) { 40 | var bang_alias = bangs[i].bang.split(" "); 41 | for (j = 0; j < bang_alias.length; j++) { 42 | if (bang == "!" + bang_alias[j]) { 43 | use_bang(bang, bangs[i].url, raw_search, "@search@", true); 44 | return; 45 | } 46 | } 47 | } 48 | 49 | } 50 | //check normal list 51 | if (result.onlycustom != true) { 52 | checklocal(); 53 | } 54 | 55 | 56 | 57 | 58 | function checklocal() { 59 | browser.storage.local.get(['banglist'], function (result) { 60 | var banglist = result.banglist; 61 | if (banglist == null || banglist == "") { 62 | console.log("first run"); 63 | load_bangsjson(check); 64 | } else { 65 | check(banglist); 66 | } 67 | }); 68 | 69 | function load_bangsjson(check) { 70 | get_file(browser.runtime.getURL('banglist/bangs.json'), "json", function (response) { 71 | var bl = JSON.stringify(response); 72 | browser.storage.local.set({ 73 | "banglist": bl 74 | }); 75 | check(bl); 76 | }); 77 | 78 | } 79 | 80 | function check(bl) { 81 | var found = false; 82 | var banglist = JSON.parse(bl); 83 | for (var i = 0; i < banglist.length; i++) { 84 | if ("!" + banglist[i].t == bang.toLowerCase()) { 85 | console.log("using local list"); 86 | use_bang(bang.toLowerCase(), banglist[i].u, raw_search, "{{{s}}}", false); 87 | found = true; 88 | break; 89 | } 90 | } 91 | if (!found) { 92 | normalsearch(); 93 | } 94 | 95 | } 96 | 97 | } 98 | 99 | function normalsearch() { 100 | if (search_url != null) { 101 | var URL = search_url.replace("@search@", encodeURIComponent(search)); 102 | update_tab(URL); 103 | } 104 | } 105 | 106 | function update_tab(url) { 107 | // `!blogspot` returns `/?q={{{s}}}+site:blogspot.com` 108 | // Turn relative URLs like above into absolute URLs 109 | // Already absolute URLs are left unchanged 110 | url = new URL(url, 'https://duckduckgo.com/').href; 111 | browser.runtime.getPlatformInfo().then((info) => { 112 | let updateProperties; 113 | //android doesn't support the loadReplace option. 114 | if (info.os == "android") { 115 | updateProperties = { url }; 116 | } 117 | else { 118 | updateProperties = { 119 | loadReplace: replace, 120 | url 121 | }; 122 | } 123 | if (tab_id != null) { 124 | browser.tabs.update(tab_id, updateProperties); 125 | } else { 126 | browser.tabs.update(updateProperties); 127 | } 128 | } 129 | 130 | ); 131 | 132 | 133 | } 134 | 135 | function use_bang(bang, bang_url, raw_search, id, custom) { 136 | var url = ""; 137 | 138 | //user internal bang list 139 | if(result.useddg != true || custom == true){ 140 | if (raw_search != "") { url = bang_url.replace(id, encodeURIComponent(raw_search)); } 141 | else { 142 | var u = new URL(bang_url); 143 | url = u.protocol + "//" + u.hostname; 144 | } 145 | } 146 | // use ddgs search 147 | else{ 148 | url = "https://duckduckgo.com/?q="+bang + " " + encodeURIComponent(raw_search); 149 | } 150 | update_tab(url); 151 | } 152 | 153 | }); 154 | } 155 | 156 | function get_file(url, type, callback) { 157 | var req = new XMLHttpRequest(); 158 | req.responseType = type; 159 | req.open('GET', url, true); 160 | req.onload = function() { 161 | callback(req.response); 162 | }; 163 | req.send(null); 164 | 165 | } 166 | -------------------------------------------------------------------------------- /plugin/banglist/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 260 3 | } 4 | -------------------------------------------------------------------------------- /plugin/grant_permissions.js: -------------------------------------------------------------------------------- 1 | 2 | browser.runtime.onInstalled.addListener((details) => { 3 | browser.permissions.contains({ 4 | permissions: ['tabs'], 5 | origins: [ 6 | "https://duckduckgo.com/bang_lite.html", 7 | "http://www.google.com/search*", 8 | "http://www.google.co.jp/search*", 9 | "http://www.google.co.uk/search*", 10 | "http://www.google.es/search*", 11 | "http://www.google.ca/search*", 12 | "http://www.google.de/search*", 13 | "http://www.google.it/search*", 14 | "http://www.google.fr/search*", 15 | "http://www.google.com.au/search*", 16 | "http://www.google.com.tw/search*", 17 | "http://www.google.nl/search*", 18 | "http://www.google.com.br/search*", 19 | "http://www.google.com.tr/search*", 20 | "http://www.google.be/search*", 21 | "http://www.google.com.gr/search*", 22 | "http://www.google.co.in/search*", 23 | "http://www.google.com.mx/search*", 24 | "http://www.google.dk/search*", 25 | "http://www.google.com.ar/search*", 26 | "http://www.google.ch/search*", 27 | "http://www.google.cl/search*", 28 | "http://www.google.at/search*", 29 | "http://www.google.co.kr/search*", 30 | "http://www.google.ie/search*", 31 | "http://www.google.com.co/search*", 32 | "http://www.google.pl/search*", 33 | "http://www.google.pt/search*", 34 | "http://www.google.com.pk/search*", 35 | "https://www.google.com/search*", 36 | "https://www.google.co.jp/search*", 37 | "https://www.google.co.uk/search*", 38 | "https://www.google.es/search*", 39 | "https://www.google.ca/search*", 40 | "https://www.google.de/search*", 41 | "https://www.google.it/search*", 42 | "https://www.google.fr/search*", 43 | "https://www.google.com.au/search*", 44 | "https://www.google.com.tw/search*", 45 | "https://www.google.nl/search*", 46 | "https://www.google.com.br/search*", 47 | "https://www.google.com.tr/search*", 48 | "https://www.google.be/search*", 49 | "https://www.google.com.gr/search*", 50 | "https://www.google.co.in/search*", 51 | "https://www.google.com.mx/search*", 52 | "https://www.google.dk/search*", 53 | "https://www.google.com.ar/search*", 54 | "https://www.google.ch/search*", 55 | "https://www.google.cl/search*", 56 | "https://www.google.at/search*", 57 | "https://www.google.co.kr/search*", 58 | "https://www.google.ie/search*", 59 | "https://www.google.com.co/search*", 60 | "https://www.google.pl/search*", 61 | "https://www.google.pt/search*", 62 | "https://www.google.com.pk/search*", 63 | "https://*.startpage.com/do/dsearch*", 64 | "https://*.startpage.com/do/metasearch.pl*", 65 | "https://www.bing.com/search*", 66 | "https://*.ecosia.org/search*", 67 | "https://*.qwant.com/*" 68 | ] 69 | }, (result) => { 70 | if (result) { 71 | // The extension has the permissions, so we do nothing 72 | } else { 73 | //ask for permissions 74 | let URL = browser.runtime.getURL("permissions_page.html"); 75 | browser.tabs.create({ url: URL }); 76 | } 77 | }); 78 | }) -------------------------------------------------------------------------------- /plugin/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sophie-glk/bang/2cee0c4e20861928a7e4fcc174732536c097699f/plugin/icon.png -------------------------------------------------------------------------------- /plugin/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Bang!", 3 | "version": "2.8", 4 | "browser_specific_settings": { 5 | "gecko": { 6 | "id": "bangs@tt7753", 7 | "strict_min_version": "109.0" 8 | } 9 | }, 10 | "options_ui": { 11 | "page": "options.html" 12 | }, 13 | "description": "An extension to add duckduckgo bangs to various search engines", 14 | "background": { 15 | "scripts": [ 16 | "background.js", 17 | "bang.js", 18 | "update.js", 19 | "shared_functions.js", 20 | "grant_permissions.js" 21 | ] 22 | }, 23 | "content_scripts": [ 24 | { 25 | "matches": [ 26 | "https://*.startpage.com/*" 27 | ], 28 | "js": [ 29 | "search_engine.js", 30 | "startpage.js", 31 | "shared_functions.js" 32 | ] 33 | } 34 | ], 35 | "permissions": [ 36 | "webRequest", 37 | "tabs", 38 | "storage", 39 | "webRequestBlocking" 40 | ], 41 | "host_permissions": [ 42 | "https://duckduckgo.com/bang_lite.html", 43 | "http://www.google.com/search*", 44 | "http://www.google.co.jp/search*", 45 | "http://www.google.co.uk/search*", 46 | "http://www.google.es/search*", 47 | "http://www.google.ca/search*", 48 | "http://www.google.de/search*", 49 | "http://www.google.it/search*", 50 | "http://www.google.fr/search*", 51 | "http://www.google.com.au/search*", 52 | "http://www.google.com.tw/search*", 53 | "http://www.google.nl/search*", 54 | "http://www.google.com.br/search*", 55 | "http://www.google.com.tr/search*", 56 | "http://www.google.be/search*", 57 | "http://www.google.com.gr/search*", 58 | "http://www.google.co.in/search*", 59 | "http://www.google.com.mx/search*", 60 | "http://www.google.dk/search*", 61 | "http://www.google.com.ar/search*", 62 | "http://www.google.ch/search*", 63 | "http://www.google.cl/search*", 64 | "http://www.google.at/search*", 65 | "http://www.google.co.kr/search*", 66 | "http://www.google.ie/search*", 67 | "http://www.google.com.co/search*", 68 | "http://www.google.pl/search*", 69 | "http://www.google.pt/search*", 70 | "http://www.google.com.pk/search*", 71 | "https://www.google.com/search*", 72 | "https://www.google.co.jp/search*", 73 | "https://www.google.co.uk/search*", 74 | "https://www.google.es/search*", 75 | "https://www.google.ca/search*", 76 | "https://www.google.de/search*", 77 | "https://www.google.it/search*", 78 | "https://www.google.fr/search*", 79 | "https://www.google.com.au/search*", 80 | "https://www.google.com.tw/search*", 81 | "https://www.google.nl/search*", 82 | "https://www.google.com.br/search*", 83 | "https://www.google.com.tr/search*", 84 | "https://www.google.be/search*", 85 | "https://www.google.com.gr/search*", 86 | "https://www.google.co.in/search*", 87 | "https://www.google.com.mx/search*", 88 | "https://www.google.dk/search*", 89 | "https://www.google.com.ar/search*", 90 | "https://www.google.ch/search*", 91 | "https://www.google.cl/search*", 92 | "https://www.google.at/search*", 93 | "https://www.google.co.kr/search*", 94 | "https://www.google.ie/search*", 95 | "https://www.google.com.co/search*", 96 | "https://www.google.pl/search*", 97 | "https://www.google.pt/search*", 98 | "https://www.google.com.pk/search*", 99 | "https://*.startpage.com/do/dsearch*", 100 | "https://*.startpage.com/do/metasearch.pl*", 101 | "https://www.bing.com/search*", 102 | "https://*.ecosia.org/search*", 103 | "https://*.qwant.com/*" 104 | ], 105 | "web_accessible_resources": [ 106 | { 107 | "resources": [ 108 | "banglist/bangs.json" 109 | ], 110 | "matches": [ 111 | "*://*/*" 112 | ], 113 | "resources": [ 114 | "banglist/version.json" 115 | ], 116 | "matches": [ 117 | "*://*/*" 118 | ] 119 | } 120 | ], 121 | "icons": { 122 | "256": "icon.png" 123 | }, 124 | "manifest_version": 3 125 | } -------------------------------------------------------------------------------- /plugin/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Bang Prefix:
9 | 11 |12 |
Usage: Bang in the first column, url in the second one. The location where the search request has to be placed is denoted with @search@. You can specify multiple names for the same bang, just seperate them with spaces. All urls have to be valid URLs e.g https://example.com?q=@search@
15 |20 | Only use custom bangs: 21 | 22 |
23 |24 | Use DuckDuckGo to resolve bangs: 25 | 26 |
27 | 28 |29 | 30 |
31 |32 | 33 |
34 |35 | 36 | 37 |
38 |39 | 40 |
41 |42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /plugin/options.js: -------------------------------------------------------------------------------- 1 | function restore_options() { 2 | chrome.storage.sync.get(['bangs', 'prefix', 'onlycustom', 'useddg'], function(result) { 3 | if (result.prefix != null) { 4 | document.getElementById("prefix").value = result.prefix; 5 | } 6 | if(result.onlycustom != null){ 7 | document.getElementById("onlycustom").checked = result.onlycustom; 8 | } 9 | if(result.useddg != null){ 10 | document.getElementById("useddg").checked = result.useddg; 11 | } 12 | if (result.bangs != null) { 13 | var bangs = JSON.parse(result.bangs); 14 | var i; 15 | for (i = 0; i < bangs.length; i++) { 16 | addline(bangs[i].bang, bangs[i].url, i); 17 | } 18 | } 19 | }); 20 | } 21 | 22 | function addline(bang, url, i) { 23 | 24 | var p = document.getElementById("prefix").value; 25 | var prefix = "!"; 26 | if (p != "" && p != null) { 27 | prefix = p; 28 | } 29 | var list = document.getElementById("list"); 30 | var d = document.createElement("div"); 31 | d.id = "d" + i; 32 | var exl = document.createTextNode(prefix + " "); 33 | var space = document.createTextNode(" "); 34 | var br = document.createElement("br"); 35 | var button = document.createElement("button"); 36 | button.innerHTML = '-'; 37 | button.id = "bu" + i; 38 | button.addEventListener("click", function(event) { 39 | var i = event.target.id.replace("bu", ""); 40 | document.getElementById("d" + i).outerHTML = ""; 41 | 42 | }); 43 | 44 | var inpb = document.createElement("input"); 45 | inpb.value = bang; 46 | inpb.style = "width:21%" 47 | inpb.classList.add("bang"); 48 | inpb.id = "ba" + i; 49 | 50 | 51 | var inpu = document.createElement("input"); 52 | inpu.value = url; 53 | inpu.style = "width:70.5%"; 54 | inpu.classList.add("url"); 55 | inpu.id = "u" + i; 56 | 57 | d.appendChild(exl); 58 | d.appendChild(inpb); 59 | d.appendChild(space); 60 | d.appendChild(inpu); 61 | d.appendChild(space); 62 | d.appendChild(button); 63 | d.appendChild(br); 64 | list.appendChild(d); 65 | } 66 | 67 | function save_options() { 68 | 69 | var bangs = document.getElementsByClassName("bang"); 70 | var urls = document.getElementsByClassName("url"); 71 | var prefix = document.getElementById("prefix").value[0]; 72 | let onlycustom = document.getElementById("onlycustom").checked; 73 | let useddg = document.getElementById("useddg").checked; 74 | 75 | var i; 76 | var ba = []; 77 | for (i = 0; i < bangs.length; i++) { 78 | var x = bangs[i].value; 79 | var y = urls[i].value; 80 | if (x != "" && y != "") { 81 | var bang = { 82 | "bang": x, 83 | "url": y 84 | } 85 | ba.push(bang); 86 | } 87 | } 88 | var save = JSON.stringify(ba); 89 | chrome.storage.sync.set({ 90 | "bangs": save, 91 | "onlycustom": onlycustom, 92 | "prefix": prefix, 93 | "useddg": useddg 94 | 95 | }); 96 | 97 | location.reload(); 98 | } 99 | 100 | function import_settings() { 101 | var inp = document.getElementById('import_input'); 102 | inp.click(); 103 | inp.addEventListener('change', function(e) { 104 | var reader = new FileReader(); 105 | reader.onload = function(e) { 106 | try { 107 | var st = JSON.parse(this.result); 108 | if (st.ddb) { 109 | chrome.storage.sync.set({ 110 | "bangs": st.bangs, 111 | "onlycustom": st.onlycustom, 112 | "prefix": st.prefix, 113 | "useddg": useddg 114 | 115 | }); 116 | location.reload(); 117 | } 118 | } catch (e) { 119 | console.log(e); 120 | } 121 | }; 122 | reader.readAsText(this.files[0]); 123 | 124 | 125 | }); 126 | } 127 | 128 | function export_settings() { 129 | chrome.storage.sync.get(['bangs', 'prefix', 'onlycustom', 'useddg'], function(result) { 130 | var output = { 131 | "bangs": result.bangs, 132 | "onlycustom": result.onlycustom, 133 | "prefix": result.prefix, 134 | "useddg": result.useddg, 135 | "ddb": true 136 | }; 137 | var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(output)); 138 | var downloadAnchorNode = document.createElement('a'); 139 | downloadAnchorNode.setAttribute("href", dataStr); 140 | downloadAnchorNode.setAttribute("download", "settings.json"); 141 | document.body.appendChild(downloadAnchorNode); 142 | downloadAnchorNode.click(); 143 | downloadAnchorNode.remove(); 144 | }); 145 | } 146 | 147 | 148 | document.addEventListener('DOMContentLoaded', restore_options); 149 | document.getElementById('review').addEventListener('click', function() { 150 | window.open("https://addons.mozilla.org/en-US/firefox/addon/tt7753bang/"); 151 | }); 152 | document.getElementById('bug').addEventListener('click', function() { 153 | window.open("https://github.com/sophie-glk/bang/issues"); 154 | }); 155 | document.getElementById('save').addEventListener('click', save_options); 156 | document.getElementById('import').addEventListener('click', import_settings); 157 | document.getElementById('export').addEventListener('click', export_settings); 158 | document.getElementById('add').addEventListener('click', function() { 159 | addline("", "", document.getElementsByClassName("bang").length); 160 | }); 161 | -------------------------------------------------------------------------------- /plugin/permissions_page.css: -------------------------------------------------------------------------------- 1 | .container { 2 | position: absolute; 3 | top: 50%; 4 | left: 50%; 5 | -moz-transform: translateX(-50%) translateY(-50%); 6 | -webkit-transform: translateX(-50%) translateY(-50%); 7 | transform: translateX(-50%) translateY(-50%); 8 | } -------------------------------------------------------------------------------- /plugin/permissions_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |