diff --git a/src/contentScript.js b/src/contentScript.js
index cea8bcc..67f68db 100644
--- a/src/contentScript.js
+++ b/src/contentScript.js
@@ -51,17 +51,45 @@ function checkForShouldKillSticky(result) {
return shouldKillSticky;
}
+/* 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) => {
+ var shouldKillSticky = false;
+ for (var mutation of mutationsList) {
+ if (mutation.target.style.position == 'fixed' ||
+ mutation.target.style.position == 'sticky')
+ shouldKillSticky = true;
+ }
+ if (shouldKillSticky)
+ requestAnimationFrame(() => { killSticky(); });
+ });
+
+ observer.observe(document.querySelector("body"), {
+ attributes: true,
+ childList: true,
+ subtree: true
+ });
+}
+
/******************/
/* INITIALIZATION */
/******************/
function initialize() {
- chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ],
+ chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode", "constantVigilance" ],
(result) => {
let shouldKillSticky = checkForShouldKillSticky(result);
updateIcon(shouldKillSticky);
+ let constantVigilance = (result.constantVigilance == "false") ? false : true;
window.onload = () => {
- if (shouldKillSticky) killSticky();
+ if (shouldKillSticky) {
+ killSticky();
+ if (constantVigilance) startConstantVigilance();
+ }
};
});
}
diff --git a/src/options.css b/src/options.css
index 150386d..49089c1 100644
--- a/src/options.css
+++ b/src/options.css
@@ -81,7 +81,7 @@ textarea {
display: flex;
flex-flow: row wrap;
align-items: center;
- max-width: 640px;
+ max-width: 750px;
}
.top-controls .buttons {
display: flex;
@@ -121,6 +121,18 @@ button:focus:active {
background-color: #777;
opacity: 0.3;
}
+.top-controls button:not(:disabled):hover {
+ text-shadow:
+ 0 0 1px #fff,
+ 0 0 3px #fff,
+ 0 0 5px #fff;
+ cursor: pointer;
+}
+
+/******************/
+/* MODE SELECTION */
+/******************/
+
input#whitelist-mode {
display: block;
-webkit-appearance: none;
@@ -153,6 +165,7 @@ input#whitelist-mode,
align-self: flex-start;
border: 1px solid #ddd;
padding: 8px 10px;
+ margin
cursor: default;
background-color: #fff;
}
@@ -173,15 +186,59 @@ input#whitelist-mode,
.mode-select-container span:not(.disabled):hover {
border-bottom: 1px solid currentColor;
}
-.top-controls button:not(:disabled):hover {
- text-shadow:
- 0 0 1px #fff,
- 0 0 3px #fff,
- 0 0 5px #fff;
+
+/**********************/
+/* CONSTANT VIGILANCE */
+/**********************/
+
+.constant-vigilance-container {
+ border: 1px solid #ddd;
+ padding: 9px 13px 12px 11px;
+ display: flex;
+ align-items: center;
+ margin: 0 0 0 10px;
+}
+
+.constant-vigilance-container input[type='checkbox'] {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ border: 1px solid #000;
+ width: 15px;
+ height: 15px;
+ position: relative;
+ top: 1px;
+ margin: 3px 5px 0 0;
+}
+.constant-vigilance-container input[type='checkbox'],
+.constant-vigilance-container label {
cursor: pointer;
}
-p.note {
- font-size: 0.875em;
+.constant-vigilance-container label {
+ line-height: 1;
+ padding: 8px 0 0 0;
+ border-bottom: 1px solid transparent;
+ font-size: 0.875rem;
+}
+.constant-vigilance-container label::selection {
+ background-color: transparent;
+}
+.constant-vigilance-container input[type='checkbox']:focus {
+ outline: none;
+}
+.constant-vigilance-container input[type='checkbox']:focus + label,
+.constant-vigilance-container input[type='checkbox']:hover + label,
+.constant-vigilance-container input[type='checkbox'] + label:hover {
+ border-bottom: 1px dotted #000;
+}
+.constant-vigilance-container input[type='checkbox']:checked,
+.constant-vigilance-container input[type='checkbox']:hover {
+ box-shadow: 0 0 0 2px #fff inset;
+}
+.constant-vigilance-container input[type='checkbox']:hover {
+ background-color: #ccc;
+}
+.constant-vigilance-container input[type='checkbox']:checked {
+ background-color: #000;
}
/******************/
@@ -341,3 +398,6 @@ code {
.fa-heavy {
font-weight: 900;
}
+p.note {
+ font-size: 0.875em;
+}
diff --git a/src/options.html b/src/options.html
index 191b79b..3e5aec9 100644
--- a/src/options.html
+++ b/src/options.html
@@ -16,6 +16,10 @@
Whitelist mode
+
+
+
+
diff --git a/src/options.js b/src/options.js
index cc731ae..0015c20 100644
--- a/src/options.js
+++ b/src/options.js
@@ -49,10 +49,12 @@ 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";
+ let constantVigilance = document.querySelector("input#constant-vigilance").checked ? "true" : "false";
chrome.storage.sync.set({
"matchingPatterns": matchingPatterns,
"exclusionPatterns": exclusionPatterns,
- "mode": mode
+ "mode": mode,
+ "constantVigilance": constantVigilance
}, () => { setButtonsActive(false); });
}
@@ -60,16 +62,20 @@ function saveChanges() {
discarding the user's changes.
*/
function resetChanges(callback) {
- chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], (result) => {
+ chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode", "constantVigilance" ], (result) => {
AKS.matchingPatterns = result.matchingPatterns || "";
AKS.exclusionPatterns = result.exclusionPatterns || ""
AKS.mode = result.mode || "blacklist";
+ AKS.constantVigilance = result.constantVigilance || "true";
document.querySelector("#matchingPatterns textarea").value = AKS.matchingPatterns;
document.querySelector("#exclusionPatterns textarea").value = AKS.exclusionPatterns;
toggleModeSelectorState(AKS.mode);
+ // Set CONSTANT VIGILANCE! checkbox state.
+ document.querySelector("input#constant-vigilance").checked = AKS.constantVigilance == "true";
+
// De-activate the "Reset" and "Save" buttons.
setButtonsActive(false);
@@ -160,7 +166,7 @@ function initialize() {
});
// Listeners for mode select switch.
- document.querySelector("input[type='checkbox']").addEventListener("change", (event) => {
+ document.querySelector("input#whitelist-mode").addEventListener("change", (event) => {
modeSelectorInputReceived();
});
document.querySelectorAll(".mode-select-container span").forEach(span => {
@@ -169,6 +175,12 @@ function initialize() {
});
});
+ /* Listener to activate Reset/Save buttons when the CONSTANT VIGILANCE
+ checkbox is toggled. */
+ document.querySelector("input#constant-vigilance").addEventListener("change", (event) => {
+ setButtonsActive(true);
+ });
+
// Listener for open help button.
document.querySelector(".open-help-button").addActivateEvent((event) => {
setHelpOverlayVisible(true);