diff --git a/background.js b/background.js new file mode 100644 index 0000000..ad5dc1c --- /dev/null +++ b/background.js @@ -0,0 +1,10 @@ +chrome.runtime.onInstalled.addListener(() => { + chrome.declarativeContent.onPageChanged.removeRules(undefined, () => { + chrome.declarativeContent.onPageChanged.addRules([{ + conditions: [ new chrome.declarativeContent.PageStateMatcher({ + pageUrl: { }, + }) + ], actions: [ new chrome.declarativeContent.ShowPageAction() ] + }]); + }); +}); \ No newline at end of file diff --git a/fonts/fa-light-300.ttf b/fonts/fa-light-300.ttf new file mode 100644 index 0000000..a433f45 Binary files /dev/null and b/fonts/fa-light-300.ttf differ diff --git a/fonts/fa-regular-400.ttf b/fonts/fa-regular-400.ttf new file mode 100644 index 0000000..b2599e0 Binary files /dev/null and b/fonts/fa-regular-400.ttf differ diff --git a/fonts/fa-solid-900.ttf b/fonts/fa-solid-900.ttf new file mode 100644 index 0000000..58c9a9f Binary files /dev/null and b/fonts/fa-solid-900.ttf differ diff --git a/fonts/font-awesome.css b/fonts/font-awesome.css new file mode 100644 index 0000000..664cfe2 --- /dev/null +++ b/fonts/font-awesome.css @@ -0,0 +1,25 @@ +/****************/ +/* 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; +} + diff --git a/manifest.json b/manifest.json index d0d9119..235be9a 100644 --- a/manifest.json +++ b/manifest.json @@ -4,16 +4,22 @@ "version": "0.3", "description": "Get rid of sticky elements on websites - permanently!", "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": [ { "matches": [ "http://*/*", "https://*/*" ], "run_at": "document_end", - "js": [ "contentScript.js" ] + "js": [ "functions.js", "contentScript.js" ] } ], "page_action": { + "default_popup": "popup.html", + "default_title": "AlwaysKillSticky - Click the icon to control sticky-killing on this site!", "default_icon": { "16": "images/ASK16.png", "32": "images/ASK32.png", diff --git a/options.css b/options.css new file mode 100644 index 0000000..010e7c6 --- /dev/null +++ b/options.css @@ -0,0 +1,173 @@ +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; +} diff --git a/options.html b/options.html index f22dfac..94ab02b 100644 --- a/options.html +++ b/options.html @@ -3,181 +3,7 @@ Always Kill Sticky - Options - +

Always Kill Sticky

diff --git a/popup.css b/popup.css new file mode 100644 index 0000000..b1f6796 --- /dev/null +++ b/popup.css @@ -0,0 +1,93 @@ +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"; +} diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..e00c9d1 --- /dev/null +++ b/popup.html @@ -0,0 +1,17 @@ + + + AlwaysKillSticky + + + + +
+ +
+
+ +
+ + + + \ No newline at end of file diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..3e54e81 --- /dev/null +++ b/popup.js @@ -0,0 +1,147 @@ +/*******************/ +/* 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(); \ No newline at end of file