| /* HELPERS */ | /* HELPERS */ | ||||
| /***********/ | /***********/ | ||||
| /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ | |||||
| /* Given the result of a query to storage (for the matching and exclusion | /* Given the result of a query to storage (for the matching and exclusion | ||||
| pattern lists, and the current mode - whitelist or blacklist), this function | pattern lists, and the current mode - whitelist or blacklist), this function | ||||
| determines whether stickies should be killed on the currently loaded page. | determines whether stickies should be killed on the currently loaded page. | ||||
| return shouldKillSticky; | return shouldKillSticky; | ||||
| } | } | ||||
| /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ | |||||
| /* This is the code that actually does the sticky killing! It simply selects | |||||
| all elements whose 'position' CSS property has a computed value of either | |||||
| 'sticky' or 'fixed', and removes those elements. | |||||
| */ | |||||
| function killSticky(root) { | |||||
| root = root || document.querySelector("body"); | |||||
| root.querySelectorAll('*').forEach(element => { | |||||
| if (getComputedStyle(element).position === 'fixed' || | |||||
| getComputedStyle(element).position === 'sticky') { | |||||
| console.log("Killing sticky!"); | |||||
| element.remove(); | |||||
| AKS.stickiesKilled++; | |||||
| chrome.runtime.sendMessage({ newBadgeText: "" + AKS.stickiesKilled }); | |||||
| } | |||||
| }); | |||||
| // Compensate for full-screen paywalls. | |||||
| restoreScrollability(); | |||||
| } | |||||
| /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ | |||||
| /* Full-screen paywalls not only bring up sticky elements, they also make | |||||
| the page un-scrollable. This ensures that the page remains scrollable. | |||||
| */ | |||||
| function restoreScrollability() { | |||||
| document.querySelectorAll("html, body").forEach(container => { | |||||
| container.style.setProperty("overflow-y", "auto", "important"); | |||||
| }); | |||||
| } | |||||
| /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ | |||||
| /* Some websites add sticky elements after loading, or make existing elements | |||||
| sticky (either on a timer, or based on user actions). CONSTANT VIGILANCE | |||||
| counteracts this behavior, by watching the DOM for mutations, and, if | |||||
| necessary, killing any newly-formed stickies. | |||||
| */ | |||||
| function startConstantVigilance() { | |||||
| var observer = new MutationObserver((mutationsList, observer) => { | |||||
| for (var mutation of mutationsList) { | |||||
| killSticky(mutation.target); | |||||
| } | |||||
| }); | |||||
| console.log("Commencing vigilance for stickies!"); | |||||
| observer.observe(document.querySelector("html"), { | |||||
| attributes: true, | |||||
| childList: true, | |||||
| subtree: true | |||||
| }); | |||||
| } | |||||
| /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ | |||||
| /* Immediately kill all stickies, then commence constant vigilance. | |||||
| */ | |||||
| function beginKillingStickies() { | |||||
| if (!window.AKS) window.AKS = { stickiesKilled: 0 }; | |||||
| killSticky(); | |||||
| startConstantVigilance(); | |||||
| } | |||||
| /******************/ | /******************/ | ||||
| /* INITIALIZATION */ | /* INITIALIZATION */ | ||||
| /******************/ | /******************/ |
| chrome.runtime.sendMessage({ "killingStickies" : shouldKillSticky, "tabID": tabID }); | chrome.runtime.sendMessage({ "killingStickies" : shouldKillSticky, "tabID": tabID }); | ||||
| } | } | ||||
| /* This is the code that actually does the sticky killing! It simply selects | |||||
| all elements whose 'position' CSS property has a computed value of either | |||||
| 'sticky' or 'fixed', and removes those elements. | |||||
| */ | |||||
| function killSticky(root) { | |||||
| root = root || document.querySelector("body"); | |||||
| root.querySelectorAll('*').forEach(element => { | |||||
| if (getComputedStyle(element).position === 'fixed' || | |||||
| getComputedStyle(element).position === 'sticky') { | |||||
| console.log("Killing sticky!"); | |||||
| element.remove(); | |||||
| } | |||||
| }); | |||||
| // Compensate for full-screen paywalls. | |||||
| restoreScrollability(); | |||||
| } | |||||
| /* Full-screen paywalls not only bring up sticky elements, they also make | |||||
| the page un-scrollable. This ensures that the page remains scrollable. | |||||
| */ | |||||
| function restoreScrollability() { | |||||
| document.querySelectorAll("html, body").forEach(container => { | |||||
| container.style.setProperty("overflow-y", "auto", "important"); | |||||
| }); | |||||
| } | |||||
| /* Some websites add sticky elements after loading, or make existing elements | |||||
| sticky (either on a timer, or based on user actions). CONSTANT VIGILANCE | |||||
| counteracts this behavior, by watching the DOM for mutations, and, if | |||||
| necessary, killing any newly-formed stickies. | |||||
| */ | |||||
| function startConstantVigilance() { | |||||
| var observer = new MutationObserver((mutationsList, observer) => { | |||||
| for (var mutation of mutationsList) { | |||||
| killSticky(mutation.target); | |||||
| } | |||||
| }); | |||||
| console.log("Commencing vigilance for stickies!"); | |||||
| observer.observe(document.querySelector("html"), { | |||||
| attributes: true, | |||||
| childList: true, | |||||
| subtree: true | |||||
| }); | |||||
| } | |||||
| /* Immediately kill all stickies, then commence constant vigilance. | |||||
| */ | |||||
| function beginKillingStickies() { | |||||
| killSticky(); | |||||
| startConstantVigilance(); | |||||
| } | |||||
| /* Enables the page action (i.e., the browser toolbar icon). | |||||
| */ | |||||
| chrome.runtime.onInstalled.addListener(() => { | |||||
| chrome.declarativeContent.onPageChanged.removeRules(undefined, () => { | |||||
| chrome.declarativeContent.onPageChanged.addRules([{ | |||||
| conditions: [ new chrome.declarativeContent.PageStateMatcher({ | |||||
| pageUrl: { schemes: [ 'http', 'https' ] }, | |||||
| }) | |||||
| ], actions: [ new chrome.declarativeContent.ShowPageAction() ] | |||||
| }]); | |||||
| }); | |||||
| }); | |||||
| /* Toggle the toolbar icon based on whether stickies are, or are not, set to | /* Toggle the toolbar icon based on whether stickies are, or are not, set to | ||||
| be killed on the current tab. | be killed on the current tab. | ||||
| tab are. | tab are. | ||||
| */ | */ | ||||
| chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||||
| let icons = request.killingStickies ? { | |||||
| "16": "images/ASK_on_16.png", | |||||
| "32": "images/ASK_on_32.png", | |||||
| "48": "images/ASK_on_48.png", | |||||
| "128": "images/ASK_on_128.png" | |||||
| } : { | |||||
| "16": "images/ASK_off_16.png", | |||||
| "32": "images/ASK_off_32.png", | |||||
| "48": "images/ASK_off_48.png", | |||||
| "128": "images/ASK_off_128.png" | |||||
| }; | |||||
| chrome.pageAction.setIcon({ | |||||
| path: icons, | |||||
| tabId: request.tabID || sender.tab.id | |||||
| }); | |||||
| if (typeof request.killingStickies != "undefined") { | |||||
| let icons = request.killingStickies ? { | |||||
| "16": "images/ASK_on_16.png", | |||||
| "32": "images/ASK_on_32.png", | |||||
| "48": "images/ASK_on_48.png", | |||||
| "128": "images/ASK_on_128.png" | |||||
| } : { | |||||
| "16": "images/ASK_off_16.png", | |||||
| "32": "images/ASK_off_32.png", | |||||
| "48": "images/ASK_off_48.png", | |||||
| "128": "images/ASK_off_128.png" | |||||
| }; | |||||
| chrome.browserAction.setIcon({ | |||||
| path: icons, | |||||
| tabId: request.tabID || sender.tab.id | |||||
| }); | |||||
| } else if (typeof request.newBadgeText != "undefined") { | |||||
| chrome.browserAction.setBadgeText({ | |||||
| tabId: sender.tab.id, | |||||
| text: request.newBadgeText | |||||
| }); | |||||
| } | |||||
| }); | |||||
| chrome.browserAction.setBadgeBackgroundColor({ | |||||
| color: "#666" | |||||
| }); | }); |
| "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://git.sr.ht/~achmizs/AlwaysKillSticky.git", | "homepage_url": "https://git.sr.ht/~achmizs/AlwaysKillSticky.git", | ||||
| "permissions": [ "declarativeContent", "activeTab", "storage" ], | |||||
| "permissions": [ "activeTab", "storage" ], | |||||
| "background": { | "background": { | ||||
| "scripts": ["background.js"], | "scripts": ["background.js"], | ||||
| "persistent": false | "persistent": false | ||||
| "js": [ "functions.js", "contentScript.js" ] | "js": [ "functions.js", "contentScript.js" ] | ||||
| } | } | ||||
| ], | ], | ||||
| "page_action": { | |||||
| "browser_action": { | |||||
| "default_popup": "popup.html", | "default_popup": "popup.html", | ||||
| "default_title": "AlwaysKillSticky - Click the icon to control sticky-killing on this site!", | "default_title": "AlwaysKillSticky - Click the icon to control sticky-killing on this site!", | ||||
| "default_icon": { | "default_icon": { |
| tab are. | tab are. | ||||
| */ | */ | ||||
| chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { | ||||
| let icons = request.killingStickies ? { | |||||
| if (typeof request.killingStickies != "undefined") { | |||||
| let icons = request.killingStickies ? { | |||||
| "19": "images/ASK_on_19.png", | "19": "images/ASK_on_19.png", | ||||
| "38": "images/ASK_on_38.png", | "38": "images/ASK_on_38.png", | ||||
| } : { | } : { | ||||
| "19": "images/ASK_off_19.png", | "19": "images/ASK_off_19.png", | ||||
| "38": "images/ASK_off_38.png", | "38": "images/ASK_off_38.png", | ||||
| }; | |||||
| chrome.browserAction.setIcon({ | |||||
| path: icons, | |||||
| tabId: request.tabID || sender.tab.id | |||||
| }); | |||||
| }; | |||||
| chrome.browserAction.setIcon({ | |||||
| path: icons, | |||||
| tabId: request.tabID || sender.tab.id | |||||
| }); | |||||
| } else if (typeof request.newBadgeText != "undefined") { | |||||
| chrome.browserAction.setBadgeText({ | |||||
| tabId: sender.tab.id, | |||||
| text: request.newBadgeText | |||||
| }); | |||||
| } | |||||
| }); | |||||
| chrome.browserAction.setBadgeBackgroundColor({ | |||||
| color: "#666" | |||||
| }); | }); |