| @@ -1,5 +1,6 @@ | |||
| window.onload = () => { | |||
| chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns" ], (result) => { | |||
| chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], | |||
| (result) => { | |||
| killStickyIfMatch(result); | |||
| }); | |||
| }; | |||
| @@ -8,7 +9,9 @@ function killStickyIfMatch(result) { | |||
| if (typeof result.matchingPatterns == "undefined") return; | |||
| var killSticky = false; | |||
| let matchingPatterns = result.matchingPatterns.split("\n"); | |||
| let matchingPatterns = result.mode == "whitelist" ? | |||
| [ ".*" ] : | |||
| result.matchingPatterns.split("\n"); | |||
| for (let pattern of matchingPatterns) { | |||
| if (location.href.match(new RegExp(pattern))) { | |||
| killSticky = true; | |||
| @@ -30,6 +30,7 @@ | |||
| } | |||
| h1 { | |||
| border-bottom: 1px solid #ddd; | |||
| margin: 0.5em 0; | |||
| } | |||
| h2 { | |||
| margin: 0; | |||
| @@ -45,6 +46,7 @@ | |||
| font-family: Inconsolata, Courier, monospace; | |||
| font-size: 1.125rem; | |||
| width: 100%; | |||
| display: block; | |||
| } | |||
| #matchingPatterns textarea { | |||
| min-height: 300px; | |||
| @@ -54,11 +56,16 @@ | |||
| } | |||
| form { | |||
| text-align: right; | |||
| margin: 0 0 1em 0; | |||
| margin: 0 0 2.5em 0; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| 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; | |||
| @@ -84,7 +91,88 @@ | |||
| } | |||
| button:disabled { | |||
| background-color: #777; | |||
| opacity: 0.5; | |||
| 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; | |||
| @@ -94,18 +182,29 @@ | |||
| <body> | |||
| <h1>Always Kill Sticky</h1> | |||
| <form> | |||
| <button disabled type='button' class='reset-button'>Reset</button> | |||
| <button disabled type='button' class='save-button'>Save</button> | |||
| <span class='mode-select-container'> | |||
| <span class='blacklist-mode-label'>Blacklist mode</span> | |||
| <input type='checkbox' id='whitelist-mode'></input> | |||
| <span class='whitelist-mode-label'>Whitelist mode</span> | |||
| </span> | |||
| <span class='buttons'> | |||
| <button disabled type='button' class='reset-button'>Reset</button> | |||
| <button disabled type='button' class='save-button'>Save</button> | |||
| </span> | |||
| </form> | |||
| <div id='matchingPatterns'> | |||
| <h2>Matching patterns</h2> | |||
| <p>Kill stickies on web page URLs matching the following <a href='https://regexr.com/' rel='nofollow'>regular expressions</a> (one per line):</p> | |||
| <textarea spellcheck="false"></textarea> | |||
| <div class='textarea-container'> | |||
| <textarea spellcheck="false"></textarea> | |||
| </div> | |||
| </div> | |||
| <div id='exclusionPatterns'> | |||
| <h2>Exclusion patterns</h2> | |||
| <p>Do <strong>not</strong> kill stickies on web page URLs matching the following <a href='https://regexr.com/' rel='nofollow'>regular expressions</a> (one per line):</p> | |||
| <textarea spellcheck="false"></textarea> | |||
| <div class='textarea-container'> | |||
| <textarea spellcheck="false"></textarea> | |||
| </div> | |||
| </div> | |||
| <p>NOTE: Exclusion patterns override matching patterns; if a page is <em>both</em> matched <em>and</em> excluded, stickies will <strong>not</strong> be killed on that page.</p> | |||
| </body> | |||
| @@ -39,36 +39,69 @@ document.querySelectorAll("button").forEach(button => { | |||
| document.querySelectorAll("textarea").forEach(textarea => { | |||
| textarea.addEventListener("input", (event) => { | |||
| document.querySelectorAll("button").forEach(button => { | |||
| button.disabled = false; | |||
| }); | |||
| setButtonsActive(true); | |||
| }); | |||
| }); | |||
| document.querySelector("input[type='checkbox']").addEventListener("change", (event) => { | |||
| modeSelectorInputReceived(); | |||
| }); | |||
| document.querySelectorAll(".mode-select-container span").forEach(span => { | |||
| span.addActivateEvent((event) => { | |||
| modeSelectorInputReceived(); | |||
| }); | |||
| }); | |||
| function modeSelectorInputReceived() { | |||
| toggleModeSelectorState(); | |||
| window.currentMode = (window.currentMode == "whitelist") ? "blacklist" : "whitelist"; | |||
| setButtonsActive(true); | |||
| } | |||
| /***********/ | |||
| /* HELPERS */ | |||
| /***********/ | |||
| function toggleModeSelectorState(newMode) { | |||
| let container = document.querySelector(".mode-select-container"); | |||
| let checkbox = document.querySelector("input#whitelist-mode"); | |||
| newMode = newMode || (container.classList.contains("whitelist") ? "blacklist" : "whitelist"); | |||
| container.classList.toggle("whitelist", (newMode == "whitelist")); | |||
| checkbox.checked = (newMode == "whitelist"); | |||
| container.querySelectorAll("span").forEach(span => { | |||
| span.classList.toggle("disabled", false); | |||
| }); | |||
| document.querySelector(`.${newMode}-mode-label`).classList.toggle("disabled", true); | |||
| document.querySelector("div#matchingPatterns").classList.toggle("disabled", (newMode == "whitelist")); | |||
| document.querySelector("div#matchingPatterns textarea").disabled = (newMode == "whitelist"); | |||
| } | |||
| function saveChanges() { | |||
| let matchingPatterns = document.querySelector("#matchingPatterns textarea").value; | |||
| let exclusionPatterns = document.querySelector("#exclusionPatterns textarea").value; | |||
| let mode = document.querySelector("input#whitelist-mode").checked ? "whitelist" : "blacklist"; | |||
| chrome.storage.sync.set({ | |||
| "matchingPatterns": matchingPatterns, | |||
| "exclusionPatterns": exclusionPatterns | |||
| }, () => { | |||
| document.querySelectorAll("button").forEach(button => { | |||
| button.disabled = true; | |||
| }); | |||
| }); | |||
| "exclusionPatterns": exclusionPatterns, | |||
| "mode": mode | |||
| }, () => { setButtonsActive(false); }); | |||
| } | |||
| function resetChanges() { | |||
| chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns" ], (result) => { | |||
| chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], (result) => { | |||
| document.querySelector("#matchingPatterns textarea").value = result.matchingPatterns; | |||
| document.querySelector("#exclusionPatterns textarea").value = result.exclusionPatterns; | |||
| document.querySelectorAll("button").forEach(button => { | |||
| button.disabled = true; | |||
| }); | |||
| window.currentMode = result.mode || "blacklist"; | |||
| toggleModeSelectorState(window.currentMode); | |||
| setButtonsActive(false); | |||
| }); | |||
| } | |||
| function setButtonsActive(active) { | |||
| document.querySelectorAll("button").forEach(button => { | |||
| button.disabled = !active; | |||
| }); | |||
| } | |||
| @@ -76,6 +109,11 @@ function resetChanges() { | |||
| /* INITIALIZATION */ | |||
| /******************/ | |||
| resetChanges(); | |||
| document.querySelector("#matchingPatterns textarea").focus(); | |||
| function initialize() { | |||
| resetChanges(); | |||
| chrome.storage.sync.get("mode", (result) => { | |||
| let divToFocus = (result.mode == "whitelist") ? "#exclusionPatterns" : "#matchingPatterns"; | |||
| document.querySelector(`${divToFocus} textarea`).focus(); | |||
| }); | |||
| } | |||
| initialize(); | |||