| chrome.runtime.onInstalled.addListener(() => { | |||||
| chrome.declarativeContent.onPageChanged.removeRules(undefined, () => { | |||||
| chrome.declarativeContent.onPageChanged.addRules([{ | |||||
| conditions: [ new chrome.declarativeContent.PageStateMatcher({ | |||||
| pageUrl: { }, | |||||
| }) | |||||
| ], actions: [ new chrome.declarativeContent.ShowPageAction() ] | |||||
| }]); | |||||
| }); | |||||
| }); |
| /****************/ | |||||
| /* FONT AWESOME */ | |||||
| /****************/ | |||||
| @font-face { | |||||
| font-family: 'Font Awesome'; | |||||
| src: url('fa-light-300.ttf') format('truetype'); | |||||
| font-weight: 300; | |||||
| font-style: normal; | |||||
| } | |||||
| @font-face { | |||||
| font-family: 'Font Awesome'; | |||||
| src: url('fa-regular-400.ttf') format('truetype'); | |||||
| font-weight: 400; | |||||
| font-style: normal; | |||||
| } | |||||
| @font-face { | |||||
| font-family: 'Font Awesome'; | |||||
| src: url('fa-solid-900.ttf') format('truetype'); | |||||
| font-weight: 900; | |||||
| font-style: normal; | |||||
| } | |||||
| "version": "0.3", | "version": "0.3", | ||||
| "description": "Get rid of sticky elements on websites - permanently!", | "description": "Get rid of sticky elements on websites - permanently!", | ||||
| "author": "Said Achmiz", | "author": "Said Achmiz", | ||||
| "homepage_url": "https://wiki.obormot.net/Main/AlwaysKillSticky", | |||||
| "permissions": [ "activeTab", "storage" ], | |||||
| "homepage_url": "https://git.sr.ht/~achmizs/AlwaysKillSticky.git", | |||||
| "permissions": [ "declarativeContent", "activeTab", "storage" ], | |||||
| "background": { | |||||
| "scripts": ["background.js"], | |||||
| "persistent": false | |||||
| }, | |||||
| "content_scripts": [ | "content_scripts": [ | ||||
| { | { | ||||
| "matches": [ "http://*/*", "https://*/*" ], | "matches": [ "http://*/*", "https://*/*" ], | ||||
| "run_at": "document_end", | "run_at": "document_end", | ||||
| "js": [ "contentScript.js" ] | |||||
| "js": [ "functions.js", "contentScript.js" ] | |||||
| } | } | ||||
| ], | ], | ||||
| "page_action": { | "page_action": { | ||||
| "default_popup": "popup.html", | |||||
| "default_title": "AlwaysKillSticky - Click the icon to control sticky-killing on this site!", | |||||
| "default_icon": { | "default_icon": { | ||||
| "16": "images/ASK16.png", | "16": "images/ASK16.png", | ||||
| "32": "images/ASK32.png", | "32": "images/ASK32.png", |
| html { | |||||
| box-sizing: border-box; | |||||
| font-size: 16px; | |||||
| } | |||||
| *, *::before, *::after { | |||||
| box-sizing: inherit; | |||||
| } | |||||
| body { | |||||
| margin: 0 auto; | |||||
| display: flex; | |||||
| flex-flow: column; | |||||
| max-width: 640px; | |||||
| min-height: 100vh; | |||||
| padding: 10px; | |||||
| font-size: 1rem; | |||||
| } | |||||
| body > div { | |||||
| border: 1px solid #ddd; | |||||
| padding: 30px 15px 15px 15px; | |||||
| position: relative; | |||||
| } | |||||
| body > div + div { | |||||
| margin: 2.5em 0 0 0; | |||||
| } | |||||
| h1 { | |||||
| border-bottom: 1px solid #ddd; | |||||
| margin: 0.5em 0; | |||||
| } | |||||
| h2 { | |||||
| margin: 0; | |||||
| background-color: #fff; | |||||
| padding: 10px 15px; | |||||
| position: absolute; | |||||
| top: calc(-1 * (0.625em + 10px)); | |||||
| left: 10px; | |||||
| border: inherit; | |||||
| } | |||||
| textarea { | |||||
| border: 1px solid #aaa; | |||||
| font-family: Inconsolata, Courier, monospace; | |||||
| font-size: 1.125rem; | |||||
| width: 100%; | |||||
| display: block; | |||||
| } | |||||
| #matchingPatterns textarea { | |||||
| min-height: 300px; | |||||
| } | |||||
| #exclusionPatterns textarea { | |||||
| min-height: 150px; | |||||
| } | |||||
| form { | |||||
| text-align: right; | |||||
| margin: 0 0 2.5em 0; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| form .buttons { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| flex: 1 1 0; | |||||
| } | |||||
| button { | |||||
| -webkit-appearance: none; | |||||
| -moz-appearance: none; | |||||
| border: 1px solid #bbb; | |||||
| color: #fff; | |||||
| padding: 10px 16px; | |||||
| cursor: default; | |||||
| margin: 0 0 0 0.5em; | |||||
| } | |||||
| button.save-button { | |||||
| background-color: #16e; | |||||
| font-size: 1.5rem; | |||||
| } | |||||
| button.reset-button { | |||||
| background-color: #d3453d; | |||||
| font-size: 1rem; | |||||
| } | |||||
| button:active { | |||||
| transform: scale(0.95); | |||||
| } | |||||
| button:focus:active { | |||||
| outline: none; | |||||
| } | |||||
| button:disabled { | |||||
| background-color: #777; | |||||
| opacity: 0.3; | |||||
| } | |||||
| input#whitelist-mode { | |||||
| display: block; | |||||
| -webkit-appearance: none; | |||||
| -moz-appearance: none; | |||||
| border: 1px solid #000; | |||||
| font-size: 1rem; | |||||
| height: 2em; | |||||
| width: 4em; | |||||
| margin: 0 6px; | |||||
| background-color: #000; | |||||
| box-shadow: | |||||
| -2em 0 0 1px #fff inset, | |||||
| 0 0 0 3px #fff inset; | |||||
| } | |||||
| input#whitelist-mode:checked { | |||||
| border: 1px solid #fff; | |||||
| background-color: #fff; | |||||
| box-shadow: | |||||
| 2em 0 0 1px #000 inset, | |||||
| 0 0 0 3px #000 inset; | |||||
| } | |||||
| input#whitelist-mode, | |||||
| .mode-select-container span { | |||||
| cursor: pointer; | |||||
| } | |||||
| .mode-select-container { | |||||
| white-space: nowrap; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| align-self: flex-start; | |||||
| border: 1px solid #ddd; | |||||
| padding: 8px 10px; | |||||
| cursor: default; | |||||
| background-color: #fff; | |||||
| } | |||||
| .mode-select-container.whitelist { | |||||
| background-color: #000; | |||||
| color: #fff; | |||||
| } | |||||
| .mode-select-container:not(.whitelist) .blacklist-mode-label, | |||||
| .mode-select-container.whitelist .whitelist-mode-label { | |||||
| border-bottom: 1px dotted currentColor; | |||||
| } | |||||
| .mode-select-container span::selection { | |||||
| background-color: transparent; | |||||
| } | |||||
| .mode-select-container span.disabled { | |||||
| pointer-events: none; | |||||
| } | |||||
| .mode-select-container span:not(.disabled):hover { | |||||
| border-bottom: 1px solid currentColor; | |||||
| } | |||||
| form button:not(:disabled):hover { | |||||
| text-shadow: | |||||
| 0 0 1px #fff, | |||||
| 0 0 3px #fff, | |||||
| 0 0 5px #fff; | |||||
| cursor: pointer; | |||||
| } | |||||
| #matchingPatterns.disabled h2 { | |||||
| color: rgba(0,0,0,0.15); | |||||
| } | |||||
| #matchingPatterns.disabled p { | |||||
| opacity: 0.2; | |||||
| } | |||||
| #matchingPatterns.disabled .textarea-container { | |||||
| position: relative; | |||||
| } | |||||
| #matchingPatterns.disabled .textarea-container::before { | |||||
| content: ".*"; | |||||
| display: flex; | |||||
| position: absolute; | |||||
| background-color: rgba(232,232,232,0.9); | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| z-index: 1; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| font-family: Inconsolata, Courier, monospace; | |||||
| font-size: 4em; | |||||
| } | |||||
| body > p { | |||||
| padding: 0 15px; | |||||
| } |
| <head> | <head> | ||||
| <title>Always Kill Sticky - Options</title> | <title>Always Kill Sticky - Options</title> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1"/> | <meta name="viewport" content="width=device-width, initial-scale=1"/> | ||||
| <style> | |||||
| html { | |||||
| box-sizing: border-box; | |||||
| font-size: 16px; | |||||
| } | |||||
| *, *::before, *::after { | |||||
| box-sizing: inherit; | |||||
| } | |||||
| body { | |||||
| margin: 0 auto; | |||||
| display: flex; | |||||
| flex-flow: column; | |||||
| max-width: 640px; | |||||
| min-height: 100vh; | |||||
| padding: 10px; | |||||
| font-size: 1rem; | |||||
| } | |||||
| body > div { | |||||
| border: 1px solid #ddd; | |||||
| padding: 30px 15px 15px 15px; | |||||
| position: relative; | |||||
| } | |||||
| body > div + div { | |||||
| margin: 2.5em 0 0 0; | |||||
| } | |||||
| h1 { | |||||
| border-bottom: 1px solid #ddd; | |||||
| margin: 0.5em 0; | |||||
| } | |||||
| h2 { | |||||
| margin: 0; | |||||
| background-color: #fff; | |||||
| padding: 10px 15px; | |||||
| position: absolute; | |||||
| top: calc(-1 * (0.625em + 10px)); | |||||
| left: 10px; | |||||
| border: inherit; | |||||
| } | |||||
| textarea { | |||||
| border: 1px solid #aaa; | |||||
| font-family: Inconsolata, Courier, monospace; | |||||
| font-size: 1.125rem; | |||||
| width: 100%; | |||||
| display: block; | |||||
| } | |||||
| #matchingPatterns textarea { | |||||
| min-height: 300px; | |||||
| } | |||||
| #exclusionPatterns textarea { | |||||
| min-height: 150px; | |||||
| } | |||||
| form { | |||||
| text-align: right; | |||||
| margin: 0 0 2.5em 0; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| } | |||||
| form .buttons { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: flex-end; | |||||
| flex: 1 1 0; | |||||
| } | |||||
| button { | |||||
| -webkit-appearance: none; | |||||
| -moz-appearance: none; | |||||
| border: 1px solid #bbb; | |||||
| color: #fff; | |||||
| padding: 10px 16px; | |||||
| cursor: default; | |||||
| margin: 0 0 0 0.5em; | |||||
| } | |||||
| button.save-button { | |||||
| background-color: #16e; | |||||
| font-size: 1.5rem; | |||||
| } | |||||
| button.reset-button { | |||||
| background-color: #d3453d; | |||||
| font-size: 1rem; | |||||
| } | |||||
| button:active { | |||||
| transform: scale(0.95); | |||||
| } | |||||
| button:focus:active { | |||||
| outline: none; | |||||
| } | |||||
| button:disabled { | |||||
| background-color: #777; | |||||
| opacity: 0.3; | |||||
| } | |||||
| input#whitelist-mode { | |||||
| display: block; | |||||
| -webkit-appearance: none; | |||||
| -moz-appearance: none; | |||||
| border: 1px solid #000; | |||||
| font-size: 1rem; | |||||
| height: 2em; | |||||
| width: 4em; | |||||
| margin: 0 6px; | |||||
| background-color: #000; | |||||
| box-shadow: | |||||
| -2em 0 0 1px #fff inset, | |||||
| 0 0 0 3px #fff inset; | |||||
| } | |||||
| input#whitelist-mode:checked { | |||||
| border: 1px solid #fff; | |||||
| background-color: #fff; | |||||
| box-shadow: | |||||
| 2em 0 0 1px #000 inset, | |||||
| 0 0 0 3px #000 inset; | |||||
| } | |||||
| input#whitelist-mode, | |||||
| .mode-select-container span { | |||||
| cursor: pointer; | |||||
| } | |||||
| .mode-select-container { | |||||
| white-space: nowrap; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| align-self: flex-start; | |||||
| border: 1px solid #ddd; | |||||
| padding: 8px 10px; | |||||
| cursor: default; | |||||
| background-color: #fff; | |||||
| } | |||||
| .mode-select-container.whitelist { | |||||
| background-color: #000; | |||||
| color: #fff; | |||||
| } | |||||
| .mode-select-container:not(.whitelist) .blacklist-mode-label, | |||||
| .mode-select-container.whitelist .whitelist-mode-label { | |||||
| border-bottom: 1px dotted currentColor; | |||||
| } | |||||
| .mode-select-container span::selection { | |||||
| background-color: transparent; | |||||
| } | |||||
| .mode-select-container span.disabled { | |||||
| pointer-events: none; | |||||
| } | |||||
| .mode-select-container span:not(.disabled):hover { | |||||
| border-bottom: 1px solid currentColor; | |||||
| } | |||||
| form button:not(:disabled):hover { | |||||
| text-shadow: | |||||
| 0 0 1px #fff, | |||||
| 0 0 3px #fff, | |||||
| 0 0 5px #fff; | |||||
| cursor: pointer; | |||||
| } | |||||
| #matchingPatterns.disabled h2 { | |||||
| color: rgba(0,0,0,0.15); | |||||
| } | |||||
| #matchingPatterns.disabled p { | |||||
| opacity: 0.2; | |||||
| } | |||||
| #matchingPatterns.disabled .textarea-container { | |||||
| position: relative; | |||||
| } | |||||
| #matchingPatterns.disabled .textarea-container::before { | |||||
| content: ".*"; | |||||
| display: flex; | |||||
| position: absolute; | |||||
| background-color: rgba(232,232,232,0.9); | |||||
| width: 100%; | |||||
| height: 100%; | |||||
| z-index: 1; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| font-family: Inconsolata, Courier, monospace; | |||||
| font-size: 4em; | |||||
| } | |||||
| body > p { | |||||
| padding: 0 15px; | |||||
| } | |||||
| </style> | |||||
| <link rel='stylesheet' type='text/css' href='options.css' /> | |||||
| </head> | </head> | ||||
| <body> | <body> | ||||
| <h1>Always Kill Sticky</h1> | <h1>Always Kill Sticky</h1> |
| html { | |||||
| font-size: 16px; | |||||
| box-sizing: border-box; | |||||
| } | |||||
| *, *::before, *::after { | |||||
| box-sizing: inherit; | |||||
| } | |||||
| body { | |||||
| margin: 0; | |||||
| padding: 0; | |||||
| } | |||||
| button { | |||||
| -webkit-appearance: none; | |||||
| -moz-appearance: none; | |||||
| background-color: #fff; | |||||
| border: none; | |||||
| cursor: pointer; | |||||
| } | |||||
| button:active { | |||||
| transform: scale(0.95); | |||||
| } | |||||
| button:focus { | |||||
| outline: none; | |||||
| } | |||||
| button::selection { | |||||
| background-color: transparent; | |||||
| } | |||||
| #main-button-container { | |||||
| display: flex; | |||||
| flex-flow: column; | |||||
| } | |||||
| #main-button-container button { | |||||
| padding: 10px; | |||||
| font-size: 6rem; | |||||
| display: flex; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| height: 150px; | |||||
| width: 150px; | |||||
| color: #ccc; | |||||
| font-family: Font Awesome, sans-serif; | |||||
| } | |||||
| #main-button-container button.active { | |||||
| color: #000; | |||||
| } | |||||
| #main-button-container button:hover { | |||||
| text-shadow: | |||||
| 0 0 1px #fff, | |||||
| 0 0 3px #fff, | |||||
| 0 0 5px #fff; | |||||
| } | |||||
| #main-button-container button:hover { | |||||
| color: #999; | |||||
| } | |||||
| #main-button-container button::before { | |||||
| content: "\F08D"; | |||||
| font-weight: 900; | |||||
| position: relative; | |||||
| top: 3px; | |||||
| } | |||||
| #main-button-container button::after { | |||||
| content: "\F05E"; | |||||
| position: absolute; | |||||
| font-weight: 300; | |||||
| color: #c00; | |||||
| opacity: 0.0; | |||||
| transform: scaleX(-1) scale(1.5); | |||||
| } | |||||
| #main-button-container button.active::after { | |||||
| opacity: 1.0; | |||||
| } | |||||
| #aux-button-container { | |||||
| display: flex; | |||||
| border-top: 1px solid #ddd; | |||||
| } | |||||
| .options-button { | |||||
| font-size: 1.125rem; | |||||
| padding: 10px; | |||||
| color: #777; | |||||
| width: 100%; | |||||
| } | |||||
| .options-button:hover { | |||||
| color: #000; | |||||
| } | |||||
| .options-button::before { | |||||
| content: "\F1DE"; | |||||
| font-family: Font Awesome; | |||||
| font-size: 0.875em; | |||||
| margin: 0 5px 0 0; | |||||
| } | |||||
| .options-button::after { | |||||
| content: "Options"; | |||||
| } |
| <html> | |||||
| <head> | |||||
| <title>AlwaysKillSticky</title> | |||||
| <link rel='stylesheet' type='text/css' href='popup.css' /> | |||||
| <link rel='stylesheet' type='text/css' href='fonts/font-awesome.css' /> | |||||
| </head> | |||||
| <body> | |||||
| <div id='main-button-container'> | |||||
| <button type='button'></button> | |||||
| </div> | |||||
| <div id='aux-button-container'> | |||||
| <button type='button' class='options-button'></button> | |||||
| </div> | |||||
| </body> | |||||
| <script src="functions.js"></script> | |||||
| <script src="popup.js"></script> | |||||
| </html> |
| /*******************/ | |||||
| /* EVENT LISTENERS */ | |||||
| /*******************/ | |||||
| /***********/ | |||||
| /* HELPERS */ | |||||
| /***********/ | |||||
| /* Toggle the current state, as represented in the ASK object. (Nothing actually | |||||
| happens until the UI state is updated, killSticky() is called (if needed), | |||||
| and the new settings are saved in storage.) | |||||
| What “toggle the current state” actually means depends on the current mode. | |||||
| [1] In blacklist mode, toggleState() does one of the following: | |||||
| (a) (if stickies are not being killed on the current page) adds a matching | |||||
| pattern (if one is not already there), and removes all applicable | |||||
| exclusion patterns; or, | |||||
| (b) (if stickies are being killed on the current page) removes all | |||||
| applicable matching patterns. | |||||
| [2] In whitelist mode, toggleState() does one of the following: | |||||
| (a) (if stickies are not being killed on the current page) removes all | |||||
| applicable exclusion patterns; or, | |||||
| (b) (if stickies are being killed on the current page) adds an exclusion | |||||
| pattern. | |||||
| */ | |||||
| function toggleState() { | |||||
| if (ASK.mode == "blacklist") { | |||||
| if (!ASK.pageMatched || ASK.pageExcluded) { | |||||
| /* In this case, stickies are NOT being killed. We must add a matching | |||||
| pattern, and remove all applicable exclusion patterns. */ | |||||
| if (!ASK.pageMatched) { | |||||
| ASK.matchingPatterns.push(regExpForCurrentTab()); | |||||
| } | |||||
| if (ASK.pageExcluded) { | |||||
| ASK.exclusionPatterns = ASK.exclusionPatterns.filter(pattern => | |||||
| !ASK.activeTabLocation.match(new RegExp(pattern)) | |||||
| ); | |||||
| } | |||||
| } else { | |||||
| /* In this case, stickies ARE being killed. We must remove all | |||||
| applicable matching patterns. */ | |||||
| ASK.matchingPatterns = ASK.matchingPatterns.filter(pattern => | |||||
| !ASK.activeTabLocation.match(new RegExp(pattern)) | |||||
| ); | |||||
| } | |||||
| } else { // if whitelist mode | |||||
| // TODO: code this! | |||||
| } | |||||
| recalculatePatternEffects(); | |||||
| } | |||||
| function regExpForCurrentTab() { | |||||
| let a = document.createElement("A"); | |||||
| a.href = ASK.activeTabLocation; | |||||
| return ".*" + a.host.replace(/\./g, "\\.") + ".*"; | |||||
| } | |||||
| function recalculatePatternEffects() { | |||||
| ASK.pageMatched = false; | |||||
| ASK.pageExcluded = false; | |||||
| for (let pattern of ASK.matchingPatterns) { | |||||
| if (ASK.activeTabLocation.match(new RegExp(pattern))) { | |||||
| ASK.pageMatched = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| for (let pattern of ASK.exclusionPatterns) { | |||||
| if (ASK.activeTabLocation.match(new RegExp(pattern))) { | |||||
| ASK.pageExcluded = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| function updateState(result) { | |||||
| ASK.mode = result.mode || "blacklist"; | |||||
| ASK.matchingPatterns = (ASK.mode == "whitelist") ? | |||||
| [ ".*" ] : | |||||
| result.matchingPatterns.split("\n"); | |||||
| ASK.exclusionPatterns = (typeof result.exclusionPatterns != "undefined" && | |||||
| result.exclusionPatterns != "") ? | |||||
| result.exclusionPatterns.split("\n") : | |||||
| [ ]; | |||||
| recalculatePatternEffects(); | |||||
| } | |||||
| function updateUIState() { | |||||
| let button = document.querySelector("#main-button-container button"); | |||||
| if (ASK.mode == "blacklist" && ASK.pageMatched && !ASK.pageExcluded) { | |||||
| button.classList.toggle("active", true); | |||||
| // button.innerHTML = "X"; | |||||
| } else if (ASK.mode == "blacklist" && (!ASK.pageMatched || ASK.pageExcluded)) { | |||||
| button.classList.toggle("active", false); | |||||
| // button.innerHTML = "O"; | |||||
| } else if (ASK.mode == "whitelist" && !ASK.pageExcluded) { | |||||
| button.classList.toggle("active", false); | |||||
| // button.innerHTML = "X"; | |||||
| } else if (ASK.mode == "whitelist" && ASK.pageExcluded) { | |||||
| button.classList.toggle("active", true); | |||||
| // button.innerHTML = "O"; | |||||
| } | |||||
| } | |||||
| /******************/ | |||||
| /* INITIALIZATION */ | |||||
| /******************/ | |||||
| function initialize() { | |||||
| window.ASK = { }; | |||||
| chrome.tabs.query({currentWindow: true, active: true}, (tabs) => { | |||||
| ASK.activeTabLocation = tabs[0].url; | |||||
| chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], (result) => { | |||||
| updateState(result); | |||||
| updateUIState(); | |||||
| }); | |||||
| }); | |||||
| document.querySelector("#main-button-container button").addActivateEvent((event) => { | |||||
| toggleState(); | |||||
| let matchingPatterns = ASK.matchingPatterns.join("\n"); | |||||
| let exclusionPatterns = ASK.exclusionPatterns.join("\n"); | |||||
| let mode = ASK.mode; | |||||
| chrome.storage.sync.set({ | |||||
| "matchingPatterns": matchingPatterns, | |||||
| "exclusionPatterns": exclusionPatterns, | |||||
| "mode": mode | |||||
| }, () => { | |||||
| updateUIState(); | |||||
| if (ASK.pageMatched && !ASK.pageExcluded) | |||||
| chrome.tabs.executeScript(null, { code: 'killSticky()' }); | |||||
| }); | |||||
| }); | |||||
| document.querySelector("#aux-button-container button").addActivateEvent((event) => { | |||||
| chrome.runtime.openOptionsPage(null); | |||||
| }); | |||||
| } | |||||
| initialize(); |