| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- /***********/
- /* HELPERS */
- /***********/
-
- /* Toggle the current state, as represented in the AKS 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 (AKS.mode == "blacklist") {
- if (!AKS.pageMatched || AKS.pageExcluded) {
- /* In this case, stickies are NOT being killed. We must add a matching
- pattern, and remove all applicable exclusion patterns. */
- if (!AKS.pageMatched) {
- addPatternForCurrentTab(AKS.matchingPatterns);
- }
- if (AKS.pageExcluded) {
- disablePatternsForCurrentTab(AKS.exclusionPatterns);
- }
- } else {
- /* In this case, stickies ARE being killed. We must remove all
- applicable matching patterns. */
- disablePatternsForCurrentTab(AKS.matchingPatterns);
- }
- } else { // if whitelist mode
- if (AKS.pageExcluded) {
- /* In this case, stickies are NOT being killed. We must remove all
- applicable exclusion patterns. */
- disablePatternsForCurrentTab(AKS.exclusionPatterns);
- } else {
- /* In this case, stickies ARE being killed. We must add an exclusion
- pattern. */
- addPatternForCurrentTab(AKS.exclusionPatterns);
- }
- }
- recalculatePatternEffects();
- }
-
- /* Given a patterns list (whether matching or exclusion), enables all patterns
- that match the current page URL, if any. If none are found, adds a new
- pattern for the current tab.
- */
- function addPatternForCurrentTab(patterns) {
- /* First, we see if there are already any existing but commented-out
- patterns that match the active tab. If so, we enable them all. */
- var existingPatternsFound = false;
- for (var i = 0; i < patterns.length; i++) {
- if (patterns[i] && patterns[i].hasPrefix("#")) {
- // Strip the leading comment characters and whitespace.
- let uncommentedPattern = patterns[i].replace(/^#[#\s]*/, "");
- // Check if the pattern matches the active tab’s URL.
- if (AKS.activeTabLocation.match(new RegExp(uncommentedPattern))) {
- // If so, replace the commented pattern.
- patterns[i] = uncommentedPattern;
- existingPatternsFound = true;
- }
- }
- }
- if (existingPatternsFound) return;
-
- /* If no existing but commented-out patterns have been found, then we’ve
- got to add a new pattern. */
- let dtf = new Intl.DateTimeFormat([],
- { month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });
- patterns.push("## " + dtf.format(new Date()) + " - " + AKS.activeTabLocation);
- patterns.push(regExpForCurrentTab());
- patterns.push("");
- }
-
- /* Given a patterns list (whether matching or exclusion), disables all patterns
- that match the current page URL.
- */
- function disablePatternsForCurrentTab(patterns) {
- for (var i = 0; i < patterns.length; i++) {
- if (patterns[i] && AKS.activeTabLocation.match(new RegExp(patterns[i])))
- patterns[i] = "# " + patterns[i];
- }
- }
-
- /* Creates a regexp that matches the current page URL. This regexp will match
- all pages on the same domain.
- */
- function regExpForCurrentTab() {
- let a = document.createElement("A");
- a.href = AKS.activeTabLocation;
- return ".*" + a.host.replace(/\./g, "\\.") + ".*";
- }
-
- /* Recalculates the values of AKS.pageMatched and AKS.pageExcluded, based on
- the contents of the matching and exclusion patterns lists.
- */
- function recalculatePatternEffects() {
- AKS.pageMatched = false;
- AKS.pageExcluded = false;
- for (let pattern of AKS.matchingPatterns) {
- if (pattern &&
- !pattern.hasPrefix("#") &&
- AKS.activeTabLocation.match(new RegExp(pattern))) {
- AKS.pageMatched = true;
- break;
- }
- }
- for (let pattern of AKS.exclusionPatterns) {
- if (pattern &&
- !pattern.hasPrefix("#") &&
- AKS.activeTabLocation.match(new RegExp(pattern))) {
- AKS.pageExcluded = true;
- break;
- }
- }
- }
-
- /* Updates the values of properties of the AKS object on the basis of the
- provided result object. Called after a document.querySelector to storage (to retrieve the
- result object).
-
- Updated properties are: the current mode, the matching and exclusion
- patterns lists, and the ‘pageMatched’ and ‘pageExcluded’ properties (which
- are computed from the patterns lists).
- */
- function updateState(result) {
- AKS.mode = result.mode || "blacklist";
- AKS.matchingPatterns = (AKS.mode == "whitelist") ?
- [ ".*" ] :
- (typeof result.matchingPatterns != "undefined" ?
- result.matchingPatterns.split("\n") :
- [ ]);
- AKS.exclusionPatterns = typeof result.exclusionPatterns != "undefined" ?
- result.exclusionPatterns.split("\n") :
- [ ];
- recalculatePatternEffects();
- }
-
- /* Updates the state of all UI elements to reflect the current values of the
- AKS object (see updateState()).
- */
- function updateUIState() {
- // The big button.
- let mainButton = document.querySelector("button.main-button");
- // The block containing the mode indicator and the “Killing stickies?” label.
- let info = document.querySelector(".info");
- // The “Killing stickies?” label.
- let statusLabel = document.querySelector(".info .status-display");
- // The “Mode:” label.
- let modeLabel = document.querySelector(".info .mode-display");
-
- var active, whitelist;
-
- /* The extension (and thus the main button) is shown as ‘active’ if:
- (a) Blacklist mode is active, the current page is matched, and NOT
- excluded; or,
- (b) Whitelist mode is active, and the current page is NOT excluded.
- */
- if (AKS.mode == "blacklist") {
- if (AKS.pageMatched && !AKS.pageExcluded) {
- active = true;
- } else {
- active = false;
- }
- } else {
- if (!AKS.pageExcluded) {
- active = false;
- } else {
- active = true;
- }
- }
-
- mainButton.classList.toggle("active", active);
- statusLabel.classList.toggle("active", active);
-
- mainButton.classList.toggle("whitelist", (AKS.mode == "whitelist"));
- info.classList.toggle("whitelist", (AKS.mode == "whitelist"));
-
- mainButton.dataset["tooltip"] = active ?
- "Click to stop killing stickies on this page" :
- "Click to kill stickies on this page";
- modeLabel.dataset["tooltip"] = (AKS.mode == "whitelist") ?
- "Stickies are killed *except* on sites you exclude" :
- "Stickies are killed *only* on specified sites";
- }
-
- /* Updates the tooltip text and position, as specified by the given element
- (in the element’s data-tooltip and data-tooltip-position-y attributes).
- */
- function updateTooltip(element) {
- let tooltip = document.querySelector(".tooltip");
- tooltip.innerHTML = element.dataset["tooltip"].replace(/\*(.+?)\*/, "<strong>$1</strong>");
- tooltip.style.top = element.dataset["tooltipPositionY"];
- }
-
- /******************/
- /* INITIALIZATION */
- /******************/
-
- function initialize() {
- window.AKS = { };
-
- // Update version.
- document.querySelector(".info-header .version").innerHTML = chrome.runtime.getManifest().version;
-
- // Retrieve saved settings.
- chrome.tabs.query({currentWindow: true, active: true}, (tabs) => {
- AKS.activeTabLocation = tabs[0].url;
- AKS.activeTabID = tabs[0].id;
- chrome.storage.sync.get([ "matchingPatterns", "exclusionPatterns", "mode" ], (result) => {
- updateState(result);
- updateUIState();
- });
- });
-
- // Listener for main button.
- document.querySelector("button.main-button").addActivateEvent((event) => {
- /* This doesn’t actually kill the stickies yet; that’s below, in the
- callback to storage.sync.set. */
- toggleState();
-
- // Prepare the changes for saving.
- var changes = {
- "exclusionPatterns": AKS.exclusionPatterns.join("\n"),
- "mode": AKS.mode
- };
- if (AKS.mode == "blacklist")
- changes.matchingPatterns = AKS.matchingPatterns.join("\n");
-
- // Save the changes.
- chrome.storage.sync.set(changes, () => {
- // Update the UI, once changes are saved.
- updateUIState();
- let reloadButton = document.querySelector("button.reload-button");
-
- /* If need be, actually kill stickies on the current page.
- Otherwise, show the reload button. */
- let shouldKillSticky = AKS.pageMatched && !AKS.pageExcluded;
- if (AKS.pageMatched && !AKS.pageExcluded) {
- chrome.tabs.executeScript(null, { code: 'killSticky()' });
- reloadButton.classList.toggle("active", false);
- } else {
- reloadButton.classList.toggle("active", true);
- }
-
- // Update the tooltip for the main button.
- updateTooltip(event.target);
-
- // Update the page action (toolbar) icon.
- updateIcon(shouldKillSticky, AKS.activeTabID);
- });
- });
-
- // Listener for Options button.
- document.querySelector("button.options-button").addActivateEvent(() => {
- chrome.runtime.openOptionsPage(null);
- });
-
- // Listener for the Help button.
- document.querySelector("button.help-button").addActivateEvent(() => {
- // TODO: code!
- });
-
- // Listener for reload button (appears when sticky-killing is toggled OFF).
- document.querySelector("button.reload-button").addActivateEvent(() => {
- chrome.tabs.update(null, { url: AKS.activeTabLocation });
- window.close();
- });
-
- // Listeners to show/hide tooltips.
- document.querySelectorAll("button, .mode-display").forEach(element => {
- let tooltip = document.querySelector(".tooltip");
- element.addEventListener("mouseenter", (event) => {
- tooltip.classList.toggle("active", true);
- updateTooltip(event.target);
- });
- element.addEventListener("mouseleave", (event) => {
- tooltip.classList.toggle("active", false);
- });
- });
- }
-
- initialize();
|