@duckduckgo/autoconsent 15.0.0 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +0 -3
- package/.github/workflows/release.yml +0 -4
- package/AGENTS.md +3 -3
- package/CHANGELOG.md +32 -0
- package/build.sh +3 -2
- package/dist/addon-firefox/background.bundle.js +8 -24
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +184 -686
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +196 -25
- package/dist/addon-firefox/popup.html +98 -5
- package/dist/addon-firefox/rule-index.json +1 -0
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +8 -24
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +184 -686
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +196 -25
- package/dist/addon-mv3/popup.html +98 -5
- package/dist/addon-mv3/rule-index.json +1 -0
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +184 -685
- package/dist/autoconsent.esm.js +184 -685
- package/dist/autoconsent.playwright.js +185 -689
- package/dist/autoconsent.standalone.js +3625 -0
- package/dist/types/cmps/base.d.ts +3 -3
- package/dist/types/cmps/trustarc-top.d.ts +1 -1
- package/dist/types/eval-handler.d.ts +3 -3
- package/dist/types/heuristics.d.ts +2 -2
- package/dist/types/types.d.ts +10 -23
- package/dist/types/web.d.ts +0 -9
- package/docs/api.md +1 -8
- package/docs/puppeteer.md +1 -3
- package/docs/rule-syntax.md +0 -17
- package/eslint.config.mjs +1 -1
- package/lib/cmps/base.ts +5 -6
- package/lib/cmps/conversant.ts +7 -4
- package/lib/cmps/trustarc-top.ts +1 -1
- package/lib/cmps/uniconsent.ts +4 -4
- package/lib/eval-handler.ts +6 -3
- package/lib/heuristics.ts +15 -15
- package/lib/types.ts +9 -21
- package/lib/utils.ts +13 -9
- package/lib/web.ts +3 -53
- package/package.json +4 -17
- package/playwright/content.ts +1 -2
- package/readme.md +3 -6
- package/rules/autoconsent/dreamlab-cmp.json +13 -0
- package/rules/build.ts +4 -23
- package/rules/compact-rules.json +1 -1
- package/rules/rule-index-builder.ts +58 -0
- package/rules/rule-index.json +1 -0
- package/rules/rules.json +1 -1
- package/standalone/content.ts +101 -0
- package/tests/dreamlab-cmp.spec.ts +3 -0
- package/tests/quantcast.spec.ts +0 -6
- package/tests-wtr/heuristics/get-actionable-popups.ts +13 -13
- package/tests-wtr/heuristics/heuristic-cmp.ts +32 -33
- package/tests-wtr/lifecycle/find-cmp.ts +5 -8
- package/tests-wtr/web/do-opt-in.test.ts +0 -1
- package/tests-wtr/web/do-opt-out.test.ts +0 -1
- package/tests-wtr/web/do-self-test.test.ts +0 -1
- package/tests-wtr/web/filter-cmps.test.ts +0 -1
- package/tests-wtr/web/receive-message-callback.test.ts +1 -2
- package/tests-wtr/web/update-state.test.ts +1 -3
- package/tsconfig.build.json +1 -1
- package/.github/workflows/update-filterlist.yml +0 -42
- package/dist/autoconsent.extra.cjs.js +0 -15709
- package/dist/autoconsent.extra.esm.js +0 -15641
- package/dist/types/cmps/consentomatic.d.ts +0 -34
- package/dist/types/consentomatic/index.d.ts +0 -2
- package/dist/types/consentomatic/tools.d.ts +0 -10
- package/dist/types/filterlist-engine.d.ts +0 -2
- package/dist/types/filterlist-utils.d.ts +0 -4
- package/dist/types/web-extra.d.ts +0 -11
- package/lib/cmps/consentomatic.ts +0 -97
- package/lib/consentomatic/index.ts +0 -252
- package/lib/consentomatic/tools.ts +0 -199
- package/lib/filterlist-engine.ts +0 -5
- package/lib/filterlist-utils.ts +0 -45
- package/lib/web-extra.ts +0 -116
- package/rules/consentomatic.json +0 -1
- package/rules/filterlist.txt +0 -18440
- package/rules/filterlists/overrides.txt +0 -4
- package/scripts/compile-filterlist.mjs +0 -63
- package/scripts/fetch-easylist.sh +0 -25
- package/scripts/rebuild-filterlist.mjs +0 -216
- package/tests/oil.spec.ts +0 -7
- package/tests/springer.spec.ts +0 -7
- package/tests/wordpressgdpr.spec.ts +0 -6
|
@@ -761,14 +761,6 @@
|
|
|
761
761
|
return parseImpl(url, 5, suffixLookup, options, getEmptyResult());
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
-
// lib/types.ts
|
|
765
|
-
var PopupHandlingModes = {
|
|
766
|
-
None: -1,
|
|
767
|
-
Reject: 0,
|
|
768
|
-
Tier1: 1,
|
|
769
|
-
Tier2: 2
|
|
770
|
-
};
|
|
771
|
-
|
|
772
764
|
// lib/utils.ts
|
|
773
765
|
function copyObject(data) {
|
|
774
766
|
if (globalThis.structuredClone) {
|
|
@@ -786,12 +778,10 @@
|
|
|
786
778
|
enableCosmeticRules: true,
|
|
787
779
|
enableGeneratedRules: true,
|
|
788
780
|
enableHeuristicDetection: false,
|
|
789
|
-
enableHeuristicAction: false,
|
|
790
781
|
enablePopupMutationObserver: false,
|
|
791
782
|
detectRetries: 20,
|
|
792
783
|
isMainWorld: false,
|
|
793
784
|
prehideTimeout: 2e3,
|
|
794
|
-
enableFilterList: false,
|
|
795
785
|
visualTest: false,
|
|
796
786
|
logs: {
|
|
797
787
|
lifecycle: false,
|
|
@@ -804,7 +794,8 @@
|
|
|
804
794
|
},
|
|
805
795
|
performanceLoggingEnabled: false,
|
|
806
796
|
heuristicPopupSearchTimeout: 100,
|
|
807
|
-
heuristicMode:
|
|
797
|
+
heuristicMode: "off"
|
|
798
|
+
// heuristic disabled by default
|
|
808
799
|
};
|
|
809
800
|
const updatedConfig = copyObject(defaultConfig);
|
|
810
801
|
for (const key of Object.keys(defaultConfig)) {
|
|
@@ -823,8 +814,8 @@
|
|
|
823
814
|
if (storedConfig.enablePopupMutationObserver === void 0) {
|
|
824
815
|
storedConfig.enablePopupMutationObserver = true;
|
|
825
816
|
}
|
|
826
|
-
if (storedConfig.
|
|
827
|
-
storedConfig.
|
|
817
|
+
if (storedConfig.heuristicMode === void 0) {
|
|
818
|
+
storedConfig.heuristicMode = "tier1";
|
|
828
819
|
}
|
|
829
820
|
if (!storedConfig.logs) {
|
|
830
821
|
storedConfig.logs = {
|
|
@@ -913,6 +904,7 @@
|
|
|
913
904
|
}
|
|
914
905
|
|
|
915
906
|
// addon/popup.ts
|
|
907
|
+
var maxRenderedRules = 100;
|
|
916
908
|
async function init() {
|
|
917
909
|
const autoconsentConfig = await storageGet("config");
|
|
918
910
|
const enabledCheckbox = document.querySelector("input#enabled");
|
|
@@ -926,8 +918,10 @@
|
|
|
926
918
|
const cosmeticOffRadio = document.querySelector("input#cosmetic-off");
|
|
927
919
|
const generatedOnRadio = document.querySelector("input#generated-on");
|
|
928
920
|
const generatedOffRadio = document.querySelector("input#generated-off");
|
|
929
|
-
const
|
|
930
|
-
const
|
|
921
|
+
const heuristicOffRadio = document.querySelector("input#heuristic-off");
|
|
922
|
+
const heuristicRejectRadio = document.querySelector("input#heuristic-reject");
|
|
923
|
+
const heuristicTier1Radio = document.querySelector("input#heuristic-tier1");
|
|
924
|
+
const heuristicTier2Radio = document.querySelector("input#heuristic-tier2");
|
|
931
925
|
const visualTestOnRadio = document.querySelector("input#visual-test-on");
|
|
932
926
|
const visualTestOffRadio = document.querySelector("input#visual-test-off");
|
|
933
927
|
const popupMutationOnRadio = document.querySelector("input#popup-mutation-on");
|
|
@@ -942,6 +936,38 @@
|
|
|
942
936
|
const logsMessagesCheckbox = document.querySelector("input#logs-messages");
|
|
943
937
|
const ruleReloadButton = document.querySelector("#reload");
|
|
944
938
|
const resetButton = document.querySelector("#reset");
|
|
939
|
+
const ruleSectionControls = {
|
|
940
|
+
generated: {
|
|
941
|
+
details: document.querySelector("#generated-rules-section"),
|
|
942
|
+
count: document.querySelector("#generated-rules-count"),
|
|
943
|
+
search: document.querySelector("#generated-rules-search"),
|
|
944
|
+
enableAll: document.querySelector("#generated-rules-enable-all"),
|
|
945
|
+
disableAll: document.querySelector("#generated-rules-disable-all"),
|
|
946
|
+
status: document.querySelector("#generated-rules-status"),
|
|
947
|
+
list: document.querySelector("#generated-rules-list")
|
|
948
|
+
},
|
|
949
|
+
generic: {
|
|
950
|
+
details: document.querySelector("#generic-rules-section"),
|
|
951
|
+
count: document.querySelector("#generic-rules-count"),
|
|
952
|
+
search: document.querySelector("#generic-rules-search"),
|
|
953
|
+
enableAll: document.querySelector("#generic-rules-enable-all"),
|
|
954
|
+
disableAll: document.querySelector("#generic-rules-disable-all"),
|
|
955
|
+
status: document.querySelector("#generic-rules-status"),
|
|
956
|
+
list: document.querySelector("#generic-rules-list")
|
|
957
|
+
},
|
|
958
|
+
code: {
|
|
959
|
+
details: document.querySelector("#code-rules-section"),
|
|
960
|
+
count: document.querySelector("#code-rules-count"),
|
|
961
|
+
search: document.querySelector("#code-rules-search"),
|
|
962
|
+
enableAll: document.querySelector("#code-rules-enable-all"),
|
|
963
|
+
disableAll: document.querySelector("#code-rules-disable-all"),
|
|
964
|
+
status: document.querySelector("#code-rules-status"),
|
|
965
|
+
list: document.querySelector("#code-rules-list")
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
let ruleIndexPromise = null;
|
|
969
|
+
let ruleIndex = null;
|
|
970
|
+
autoconsentConfig.disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
945
971
|
const [currentTab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true });
|
|
946
972
|
if (!currentTab.url || !currentTab.id) {
|
|
947
973
|
console.error("Current tab is not valid");
|
|
@@ -1007,10 +1033,14 @@
|
|
|
1007
1033
|
} else {
|
|
1008
1034
|
generatedOffRadio.checked = true;
|
|
1009
1035
|
}
|
|
1010
|
-
if (autoconsentConfig.
|
|
1011
|
-
|
|
1036
|
+
if (autoconsentConfig.heuristicMode === "reject") {
|
|
1037
|
+
heuristicRejectRadio.checked = true;
|
|
1038
|
+
} else if (autoconsentConfig.heuristicMode === "tier1") {
|
|
1039
|
+
heuristicTier1Radio.checked = true;
|
|
1040
|
+
} else if (autoconsentConfig.heuristicMode === "tier2") {
|
|
1041
|
+
heuristicTier2Radio.checked = true;
|
|
1012
1042
|
} else {
|
|
1013
|
-
|
|
1043
|
+
heuristicOffRadio.checked = true;
|
|
1014
1044
|
}
|
|
1015
1045
|
if (autoconsentConfig.visualTest) {
|
|
1016
1046
|
visualTestOnRadio.checked = true;
|
|
@@ -1060,12 +1090,22 @@
|
|
|
1060
1090
|
}
|
|
1061
1091
|
generatedOnRadio.addEventListener("change", generatedChange);
|
|
1062
1092
|
generatedOffRadio.addEventListener("change", generatedChange);
|
|
1063
|
-
function
|
|
1064
|
-
|
|
1093
|
+
function heuristicModeChange() {
|
|
1094
|
+
if (heuristicRejectRadio.checked) {
|
|
1095
|
+
autoconsentConfig.heuristicMode = "reject";
|
|
1096
|
+
} else if (heuristicTier1Radio.checked) {
|
|
1097
|
+
autoconsentConfig.heuristicMode = "tier1";
|
|
1098
|
+
} else if (heuristicTier2Radio.checked) {
|
|
1099
|
+
autoconsentConfig.heuristicMode = "tier2";
|
|
1100
|
+
} else {
|
|
1101
|
+
autoconsentConfig.heuristicMode = "off";
|
|
1102
|
+
}
|
|
1065
1103
|
storageSet({ config: autoconsentConfig });
|
|
1066
1104
|
}
|
|
1067
|
-
|
|
1068
|
-
|
|
1105
|
+
heuristicOffRadio.addEventListener("change", heuristicModeChange);
|
|
1106
|
+
heuristicRejectRadio.addEventListener("change", heuristicModeChange);
|
|
1107
|
+
heuristicTier1Radio.addEventListener("change", heuristicModeChange);
|
|
1108
|
+
heuristicTier2Radio.addEventListener("change", heuristicModeChange);
|
|
1069
1109
|
function visualTestChange() {
|
|
1070
1110
|
autoconsentConfig.visualTest = visualTestOnRadio.checked;
|
|
1071
1111
|
storageSet({ config: autoconsentConfig });
|
|
@@ -1111,10 +1151,141 @@
|
|
|
1111
1151
|
logsMessagesCheckbox.addEventListener("change", () => {
|
|
1112
1152
|
updateLogsConfig();
|
|
1113
1153
|
});
|
|
1154
|
+
async function loadRuleIndex() {
|
|
1155
|
+
if (!ruleIndexPromise) {
|
|
1156
|
+
ruleIndexPromise = fetch("./rule-index.json").then(async (res) => await res.json());
|
|
1157
|
+
}
|
|
1158
|
+
ruleIndex = await ruleIndexPromise;
|
|
1159
|
+
updateRuleCounts();
|
|
1160
|
+
return ruleIndex;
|
|
1161
|
+
}
|
|
1162
|
+
function updateRuleCounts() {
|
|
1163
|
+
if (!ruleIndex) {
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1167
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1168
|
+
const sectionRules = ruleIndex?.filter((rule) => rule.section === section) || [];
|
|
1169
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1170
|
+
const count = ruleSectionControls[section].count;
|
|
1171
|
+
count.textContent = `(${disabledInSection}/${sectionRules.length} disabled)`;
|
|
1172
|
+
count.classList.toggle("rule-count-disabled", disabledInSection > 0);
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
function setRuleEnabled(ruleName, enabled) {
|
|
1176
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1177
|
+
if (enabled) {
|
|
1178
|
+
disabledCmps.delete(ruleName);
|
|
1179
|
+
} else {
|
|
1180
|
+
disabledCmps.add(ruleName);
|
|
1181
|
+
}
|
|
1182
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1183
|
+
storageSet({ config: autoconsentConfig });
|
|
1184
|
+
updateRuleCounts();
|
|
1185
|
+
}
|
|
1186
|
+
function renderOpenRuleSections() {
|
|
1187
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1188
|
+
if (ruleSectionControls[section].details.open) {
|
|
1189
|
+
renderRuleSection(section);
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
function setRuleSectionEnabled(section, enabled) {
|
|
1194
|
+
if (!ruleIndex) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
const disabledCmps = new Set(autoconsentConfig.disabledCmps || []);
|
|
1198
|
+
ruleIndex.filter((rule) => rule.section === section).forEach((rule) => {
|
|
1199
|
+
if (enabled) {
|
|
1200
|
+
disabledCmps.delete(rule.name);
|
|
1201
|
+
} else {
|
|
1202
|
+
disabledCmps.add(rule.name);
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
autoconsentConfig.disabledCmps = Array.from(disabledCmps).sort();
|
|
1206
|
+
storageSet({ config: autoconsentConfig });
|
|
1207
|
+
updateRuleCounts();
|
|
1208
|
+
renderOpenRuleSections();
|
|
1209
|
+
}
|
|
1210
|
+
function renderRuleSection(section) {
|
|
1211
|
+
const controls = ruleSectionControls[section];
|
|
1212
|
+
if (!ruleIndex) {
|
|
1213
|
+
controls.status.textContent = "Rules are not loaded yet.";
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
const disabledCmps = autoconsentConfig.disabledCmps || [];
|
|
1217
|
+
const searchQuery = controls.search.value.trim().toLowerCase();
|
|
1218
|
+
const sectionRules = ruleIndex.filter((rule) => rule.section === section);
|
|
1219
|
+
const matchingRules = sectionRules.filter((rule) => {
|
|
1220
|
+
if (!searchQuery) {
|
|
1221
|
+
return disabledCmps.includes(rule.name);
|
|
1222
|
+
}
|
|
1223
|
+
return rule.name.toLowerCase().includes(searchQuery) || !!rule.urlPattern?.toLowerCase().includes(searchQuery);
|
|
1224
|
+
});
|
|
1225
|
+
const renderedRules = matchingRules.slice(0, maxRenderedRules);
|
|
1226
|
+
const disabledInSection = sectionRules.filter((rule) => disabledCmps.includes(rule.name)).length;
|
|
1227
|
+
controls.status.textContent = searchQuery ? `Showing ${renderedRules.length} of ${matchingRules.length} matches. ${disabledInSection} disabled.` : `Showing ${renderedRules.length} of ${disabledInSection} disabled rules. Search to find enabled rules.`;
|
|
1228
|
+
controls.list.replaceChildren(
|
|
1229
|
+
...renderedRules.map((rule) => {
|
|
1230
|
+
const checkbox = document.createElement("input");
|
|
1231
|
+
checkbox.type = "checkbox";
|
|
1232
|
+
checkbox.checked = !disabledCmps.includes(rule.name);
|
|
1233
|
+
checkbox.addEventListener("change", () => {
|
|
1234
|
+
setRuleEnabled(rule.name, checkbox.checked);
|
|
1235
|
+
renderRuleSection(section);
|
|
1236
|
+
});
|
|
1237
|
+
const label = document.createElement("label");
|
|
1238
|
+
label.className = "rule-row";
|
|
1239
|
+
label.title = rule.urlPattern ? `${rule.name}
|
|
1240
|
+
${rule.urlPattern}` : rule.name;
|
|
1241
|
+
label.append(checkbox, document.createTextNode(` ${rule.name}${rule.cosmetic ? " (cosmetic)" : ""}`));
|
|
1242
|
+
return label;
|
|
1243
|
+
})
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
async function loadAndRenderRuleSection(section) {
|
|
1247
|
+
ruleSectionControls[section].status.textContent = "Loading rules...";
|
|
1248
|
+
try {
|
|
1249
|
+
await loadRuleIndex();
|
|
1250
|
+
renderRuleSection(section);
|
|
1251
|
+
} catch (e) {
|
|
1252
|
+
console.error("Failed to load rule index", e);
|
|
1253
|
+
ruleSectionControls[section].status.textContent = "Failed to load rules.";
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1257
|
+
const controls = ruleSectionControls[section];
|
|
1258
|
+
controls.details.addEventListener("toggle", () => {
|
|
1259
|
+
if (controls.details.open) {
|
|
1260
|
+
loadAndRenderRuleSection(section);
|
|
1261
|
+
}
|
|
1262
|
+
});
|
|
1263
|
+
controls.search.addEventListener("input", () => renderRuleSection(section));
|
|
1264
|
+
controls.enableAll.addEventListener("click", async () => {
|
|
1265
|
+
await loadRuleIndex();
|
|
1266
|
+
setRuleSectionEnabled(section, true);
|
|
1267
|
+
});
|
|
1268
|
+
controls.disableAll.addEventListener("click", async () => {
|
|
1269
|
+
await loadRuleIndex();
|
|
1270
|
+
setRuleSectionEnabled(section, false);
|
|
1271
|
+
});
|
|
1272
|
+
});
|
|
1273
|
+
loadRuleIndex().catch((e) => {
|
|
1274
|
+
console.error("Failed to load rule index", e);
|
|
1275
|
+
});
|
|
1114
1276
|
ruleReloadButton.addEventListener("click", async () => {
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1277
|
+
const [compactRulesRes, fullRulesRes] = await Promise.all([fetch("./compact-rules.json"), fetch("./rules.json")]);
|
|
1278
|
+
const fullRules = await fullRulesRes.json();
|
|
1279
|
+
await storageSet({
|
|
1280
|
+
rules: await compactRulesRes.json(),
|
|
1281
|
+
fullRules: fullRules.autoconsent
|
|
1282
|
+
});
|
|
1283
|
+
ruleIndexPromise = null;
|
|
1284
|
+
ruleIndex = null;
|
|
1285
|
+
Object.keys(ruleSectionControls).forEach((section) => {
|
|
1286
|
+
if (ruleSectionControls[section].details.open) {
|
|
1287
|
+
loadAndRenderRuleSection(section);
|
|
1288
|
+
}
|
|
1118
1289
|
});
|
|
1119
1290
|
});
|
|
1120
1291
|
resetButton.addEventListener("click", async () => {
|
|
@@ -23,6 +23,52 @@
|
|
|
23
23
|
cursor: pointer;
|
|
24
24
|
border-radius: 2px;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
.rule-section {
|
|
28
|
+
margin: 0.5em 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.rule-search {
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
margin: 0.5em 0;
|
|
34
|
+
width: 100%;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.rule-actions {
|
|
38
|
+
display: flex;
|
|
39
|
+
gap: 0.5em;
|
|
40
|
+
margin: 0.5em 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.rule-actions button {
|
|
44
|
+
flex: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.rule-list {
|
|
48
|
+
border: 1px solid #ddd;
|
|
49
|
+
max-height: 12em;
|
|
50
|
+
overflow-y: auto;
|
|
51
|
+
padding: 0.25em;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.rule-row {
|
|
55
|
+
display: block;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
padding: 0.15em 0;
|
|
58
|
+
text-overflow: ellipsis;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.rule-list-status {
|
|
63
|
+
color: #666;
|
|
64
|
+
font-size: 0.9em;
|
|
65
|
+
margin: 0.25em 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.rule-count-disabled {
|
|
69
|
+
color: #b00020;
|
|
70
|
+
font-weight: bold;
|
|
71
|
+
}
|
|
26
72
|
</style>
|
|
27
73
|
</head>
|
|
28
74
|
|
|
@@ -96,16 +142,63 @@
|
|
|
96
142
|
</fieldset>
|
|
97
143
|
|
|
98
144
|
<fieldset>
|
|
99
|
-
<legend>
|
|
145
|
+
<legend>Rules</legend>
|
|
146
|
+
|
|
147
|
+
<details class="rule-section" id="generated-rules-section">
|
|
148
|
+
<summary>Generated rules <span id="generated-rules-count"></span></summary>
|
|
149
|
+
<input class="rule-search" type="search" id="generated-rules-search" placeholder="Search generated rules" />
|
|
150
|
+
<div class="rule-actions">
|
|
151
|
+
<button id="generated-rules-enable-all">Enable all</button>
|
|
152
|
+
<button id="generated-rules-disable-all">Disable all</button>
|
|
153
|
+
</div>
|
|
154
|
+
<div class="rule-list-status" id="generated-rules-status"></div>
|
|
155
|
+
<div class="rule-list" id="generated-rules-list"></div>
|
|
156
|
+
</details>
|
|
157
|
+
|
|
158
|
+
<details class="rule-section" id="generic-rules-section">
|
|
159
|
+
<summary>Generic rules <span id="generic-rules-count"></span></summary>
|
|
160
|
+
<input class="rule-search" type="search" id="generic-rules-search" placeholder="Search generic rules" />
|
|
161
|
+
<div class="rule-actions">
|
|
162
|
+
<button id="generic-rules-enable-all">Enable all</button>
|
|
163
|
+
<button id="generic-rules-disable-all">Disable all</button>
|
|
164
|
+
</div>
|
|
165
|
+
<div class="rule-list-status" id="generic-rules-status"></div>
|
|
166
|
+
<div class="rule-list" id="generic-rules-list"></div>
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
<details class="rule-section" id="code-rules-section">
|
|
170
|
+
<summary>Code-based rules <span id="code-rules-count"></span></summary>
|
|
171
|
+
<input class="rule-search" type="search" id="code-rules-search" placeholder="Search code-based rules" />
|
|
172
|
+
<div class="rule-actions">
|
|
173
|
+
<button id="code-rules-enable-all">Enable all</button>
|
|
174
|
+
<button id="code-rules-disable-all">Disable all</button>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="rule-list-status" id="code-rules-status"></div>
|
|
177
|
+
<div class="rule-list" id="code-rules-list"></div>
|
|
178
|
+
</details>
|
|
179
|
+
</fieldset>
|
|
180
|
+
|
|
181
|
+
<fieldset>
|
|
182
|
+
<legend>Handle unknown popups (heuristic rule)</legend>
|
|
183
|
+
|
|
184
|
+
<div>
|
|
185
|
+
<input type="radio" id="heuristic-off" name="heuristic-mode" value="off" checked />
|
|
186
|
+
<label for="heuristic-off">Off</label>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<div>
|
|
190
|
+
<input type="radio" id="heuristic-reject" name="heuristic-mode" value="reject" />
|
|
191
|
+
<label for="heuristic-reject">Reject when possible</label>
|
|
192
|
+
</div>
|
|
100
193
|
|
|
101
194
|
<div>
|
|
102
|
-
<input type="radio" id="heuristic-
|
|
103
|
-
<label for="heuristic-
|
|
195
|
+
<input type="radio" id="heuristic-tier1" name="heuristic-mode" value="tier1" />
|
|
196
|
+
<label for="heuristic-tier1">Acknowledge if no reject (tier 1)</label>
|
|
104
197
|
</div>
|
|
105
198
|
|
|
106
199
|
<div>
|
|
107
|
-
<input type="radio" id="heuristic-
|
|
108
|
-
<label for="heuristic-
|
|
200
|
+
<input type="radio" id="heuristic-tier2" name="heuristic-mode" value="tier2" />
|
|
201
|
+
<label for="heuristic-tier2">Accept if no reject or acknowledge (tier 2)</label>
|
|
109
202
|
</div>
|
|
110
203
|
</fieldset>
|
|
111
204
|
|