Как реализовать переключатель включения/выключения для моего расширения Chrome?

У меня есть расширение для Chrome, которое блокирует несколько веб-сайтов. Я пытаюсь сделать тумблер, чтобы он перестал блокировать сайты, когда переключатель выключен. В настоящее время у меня есть html и css, реализованные во всплывающем меню, но нет кода, который фактически отключает скрипт и удаляет блоки. Как я могу реализовать некоторый код, который отключит скрипт?

Я использую версию 111.0.5563.146 Google Chrome, версия манифеста 3.

Вот код, который у меня сейчас есть:

manifest.json

{
    "manifest_version": 3,
    "name": "On-Off Switch",
    "version": "1.0.0",
    "action": {
        "default_popup": "popup.html"
    },
    "background": {
        "service_worker": "background.js"
    },
    "declarative_net_request": {
        "rule_resources": [
            {
                "id": "ruleset_1",
                "enabled": false,
                "path": "ruleset_1.json"
            }
        ]
    },
    "permissions": [
        "declarativeNetRequest",
        "storage"
    ]
}

всплывающее окно.html

<!DOCTYPE html>
<html>
    <head>
        <title>popup</title>
    </head>
    <body>
        <p>popup</p>
        <button id = "on">On</button>
        <button id = "off">Off</button>
        <script src = "popup.js"></script>
    </body>
</html>

всплывающее окно.js

document.getElementById("on").onclick = () => {
  chrome.storage.local.set({active: true});
}

document.getElementById("off").onclick = () => {
  chrome.storage.local.set({active: false});
}

набор правил_1.json

[
    {
        "id": 1,
        "action": { "type": "block" },
        "condition": { "urlFilter": "stackoverflow.com", "resourceTypes": ["main_frame"] }
    },
    {
        "id": 2,
        "action": { "type": "block" },
        "condition": { "urlFilter": "google.com/search*", "resourceTypes": ["main_frame"] }
    }
]

фон.js

async function runtime_on_installed(details) {
    if (details.reason == "install") {
        // Store the extension's current state
        // which is determined by the "declarative_net_request" key in manifest.json
        let ruleset_ids = await chrome.declarativeNetRequest.getEnabledRulesets();
        if (ruleset_ids.length == 0) {
            // Extension is currently inactive
            await chrome.storage.local.set({active: false});
        }
        else if (ruleset_ids.length == 1) {
            // Extension is currently active
            await chrome.storage.local.set({active: true});
        }
    }
    else if (details.reason == "update") {
        // Restore the extension's stored state
        // https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#method-updateEnabledRulesets
        // "Note that the set of enabled static rulesets is persisted across sessions but not across extension updates, i.e. the rule_resources manifest key will determine the set of enabled static rulesets on each extension update."
        let { active } = chrome.storage.local.get("active");
        let ruleset_ids = await chrome.declarativeNetRequest.getEnabledRulesets();
        if (active && ruleset_ids.length == 0) {
            // Extension is supposed to be active, but is inactive
            chrome.declarativeNetRequest.updateEnabledRulesets({enableRulesetIds: ["ruleset_1"]});
        }
        else if (!active && ruleset_ids.length == 1) {
            // Extension is supposed to be inactive, but is active
            chrome.declarativeNetRequest.updateEnabledRulesets({disableRulesetIds: ["ruleset_1"]});
        }
    }
}

function storage_on_changed(changes, area_name) {
    if (area_name == "local") {
        if (changes.active.oldValue == false && changes.active.newValue == true) {
            chrome.declarativeNetRequest.updateEnabledRulesets({enableRulesetIds: ["ruleset_1"]});
        }
        else if (changes.active.oldValue == true && changes.active.newValue == false) {
            chrome.declarativeNetRequest.updateEnabledRulesets({disableRulesetIds: ["ruleset_1"]});
        }
    }
}

chrome.runtime.onInstalled.addListener(runtime_on_installed);
chrome.storage.onChanged.addListener(storage_on_changed);

На данный момент ни один блок не работает. Незадолго до этого блок stackoverflow.com работал, а блок google.com/search* — нет. Может быть, это связано с тем, как я определяю правила?

Как вы хотите переключать состояние расширения? - а) Щелкнув один раз левой кнопкой мыши по значку действия расширения ? - б) С контекстным меню? (= один раз щелкните правой кнопкой мыши значок действия расширения, затем один раз щелкните левой кнопкой мыши по нужному элементу контекстного меню) chrome.contextMenus - c) С помощью кнопки во всплывающем окне расширения? (нажмите один раз левой кнопкой мыши на значок действия расширения, откроется всплывающее окно, затем нажмите кнопку внутри всплывающего окна)

Thomas Mueller 02.04.2023 09:44

@ThomasMueller Я думал о варианте C, у меня уже есть тумблер HTML/CSS, однако он не включает и не выключает скрипт и в настоящее время бесполезен. Состояние переключателя также всегда отключается после закрытия всплывающего окна.

Nicholas Picklas 02.04.2023 18:21

Я использую Chromium 111.0.5563.146 (официальная сборка) Arch Linux (64-разрядная версия) — тот же номер версии, что и у вас. Код в вашем вопросе работает для меня. Расширение блокирует как stackoverflow.com/questions , так и google.com/search?q=test, когда оно активно. Но по умолчанию он неактивен ("enabled": false,), и его нужно активировать с помощью кнопки «Вкл.» во всплывающем окне. Кроме этого, я не могу придумать ни одной причины, по которой это не сработает.

Thomas Mueller 02.04.2023 22:02

Напоминаю: на линии let { active } = chrome.storage.local.get("active"); нужен await оператор: let { active } = await chrome.storage.local.get("active");

Thomas Mueller 02.04.2023 23:18
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
101
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вот пример.

manifest.json

{
  "name": "hoge",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "declarativeNetRequest"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_popup": "popup.html"
  }
}

всплывающее окно.html

<html>
<body>
  <button id = "add">Add</button>
  <button id = "remove">Remove</button>
  <script src = "popup.js"></script>
</body>
</html>

всплывающее окно.js

document.getElementById("add").onclick = () => {
  chrome.runtime.sendMessage({ method: "add" });
}

document.getElementById("remove").onclick = () => {
  chrome.runtime.sendMessage({ method: "remove" });
}

фон.js

const rule =
{
  "id": 1,
  "action": {
    "type": "block"
  },
  "condition": {
    "urlFilter": "stackoverflow.com",
    "resourceTypes": ["main_frame"]
  }
};

chrome.runtime.onMessage.addListener((message) => {
  switch (message.method) {
    case "add":
      chrome.declarativeNetRequest.updateDynamicRules({ addRules: [rule] });
      break;
    case "remove":
      chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: [1] });
      break;
  }
});

Я продолжаю получать ошибку rule with id 1 does not have a unique id

Nicholas Picklas 02.04.2023 08:07

Добавление идентификатора 1, когда идентификатор 1 уже существует, является ошибкой.

Norio Yamamoto 02.04.2023 09:06

Как я могу сделать этот блок поддоменом? Я могу установить что-то вроде google.com, но это не блокирует google.com/search?q...

Nicholas Picklas 02.04.2023 20:24
Ответ принят как подходящий

Это основано на ответе НориоЯмамото (поэтому я проголосовал за него), но использует статические правила.

manifest.json

{
    "manifest_version": 3,
    "name": "On-Off Switch",
    "version": "1.0.0",
    "action": {
        "default_popup": "popup.html"
    },
    "background": {
        "service_worker": "background.js"
    },
    "declarative_net_request": {
        "rule_resources": [
            {
                "id": "ruleset_1",
                "enabled": false,
                "path": "ruleset_1.json"
            }
        ]
    },
    "permissions": [
        "declarativeNetRequest",
        "storage"
    ]
}

ruleset_1.json

[
    {
        "id": 1,
        "action": { "type": "block" },
        "condition": { "urlFilter": "stackoverflow.com", "resourceTypes": ["main_frame"] }
    }
]

background.js

async function runtime_on_installed(details) {
    if (details.reason == "install") {
        // Store the extension's current state
        // which is determined by the "declarative_net_request" key in manifest.json
        let ruleset_ids = await chrome.declarativeNetRequest.getEnabledRulesets();
        if (ruleset_ids.length == 0) {
            // Extension is currently inactive
            await chrome.storage.local.set({active: false});
        }
        else if (ruleset_ids.length == 1) {
            // Extension is currently active
            await chrome.storage.local.set({active: true});
        }
    }
    else if (details.reason == "update") {
        // Restore the extension's stored state
        // https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/#method-updateEnabledRulesets
        // "Note that the set of enabled static rulesets is persisted across sessions but not across extension updates, i.e. the rule_resources manifest key will determine the set of enabled static rulesets on each extension update."
        let { active } = await chrome.storage.local.get("active");
        let ruleset_ids = await chrome.declarativeNetRequest.getEnabledRulesets();
        if (active && ruleset_ids.length == 0) {
            // Extension is supposed to be active, but is inactive
            chrome.declarativeNetRequest.updateEnabledRulesets({enableRulesetIds: ["ruleset_1"]});
        }
        else if (!active && ruleset_ids.length == 1) {
            // Extension is supposed to be inactive, but is active
            chrome.declarativeNetRequest.updateEnabledRulesets({disableRulesetIds: ["ruleset_1"]});
        }
    }
}

function storage_on_changed(changes, area_name) {
    if (area_name == "local") {
        if (changes.active.oldValue == false && changes.active.newValue == true) {
            chrome.declarativeNetRequest.updateEnabledRulesets({enableRulesetIds: ["ruleset_1"]});
        }
        else if (changes.active.oldValue == true && changes.active.newValue == false) {
            chrome.declarativeNetRequest.updateEnabledRulesets({disableRulesetIds: ["ruleset_1"]});
        }
    }
}

chrome.runtime.onInstalled.addListener(runtime_on_installed);
chrome.storage.onChanged.addListener(storage_on_changed);

popup.html

<!DOCTYPE html>
<html>
    <head>
        <title>Popup</title>
    </head>
    <body>
        <p>Popup</p>
        <button id = "on">On</button>
        <button id = "off">Off</button>
        <script src = "popup.js"></script>
    </body>
</html>

popup.js

document.getElementById("on").onclick = () => {
    chrome.storage.local.set({active: true});
}

document.getElementById("off").onclick = () => {
    chrome.storage.local.set({active: false});
}

Могу ли я (и как) использовать это, чтобы заблокировать только поддомен, например example.com/foo/bar, но не example.com в целом?

Nicholas Picklas 02.04.2023 20:59

Ничего, я неправильно понял ваш вопрос, придется подумать над этим еще немного - С "urlFilter": "google.com" он блокирует google.com/search?q=test - Кстати, /foo/bar - это путь, а не поддомен example.com — Дополнительные сведения о формате urlFilter см. в chrome.declarativeNetRequest > Rules и chrome.declarativeNetRequest > RuleCondition > urlFilter

Thomas Mueller 02.04.2023 21:04

Это блокирует путь, но также блокирует google.com в целом. Мне нужно, чтобы заблокировать путь, не блокируя весь сайт. Вставка google.com/search?q=a, похоже, ничего не блокирует. Спасибо за исправление.

Nicholas Picklas 02.04.2023 21:10
"urlFilter": "google.com/search*" блокирует google.com/search?q=a, но не google.com. Прочтите документацию и, если формат urlFilter недостаточно точен, используйте regexFilter.
Thomas Mueller 02.04.2023 21:14

Кажется, это не работает для меня. Я использую тот же код, что и вы, за исключением дополнительного правила, которое я добавил. Этот код работает для вас?

Nicholas Picklas 02.04.2023 21:27

Меня устраивает. Я всегда тестирую свой код перед публикацией, иначе он обычно полон ошибок :-) Чтобы помочь вам, мне нужна ваша версия Chrome, полный код вашего расширения, пошаговые инструкции по воспроизведению проблемы, ожидаемые результаты, и фактические результаты. Отредактируйте свой вопрос с этой информацией.

Thomas Mueller 02.04.2023 21:30

Хорошо, я добавил свой текущий код к вопросу. Как я уже сказал, мой код в настоящее время почти такой же, как ваш, так как я все еще пытаюсь заставить его работать.

Nicholas Picklas 02.04.2023 21:39

Другие вопросы по теме