@duckduckgo/autoconsent 14.0.1 → 14.2.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.
Files changed (53) hide show
  1. package/.github/actions/setup-release-scripts/action.yml +1 -1
  2. package/.github/workflows/checks.yml +4 -4
  3. package/.github/workflows/release.yml +2 -2
  4. package/.github/workflows/update-filterlist.yml +2 -2
  5. package/CHANGELOG.md +43 -0
  6. package/api.md +1 -0
  7. package/dist/addon-firefox/background.bundle.js +11 -2
  8. package/dist/addon-firefox/content.bundle.js +510 -347
  9. package/dist/addon-firefox/manifest.json +1 -1
  10. package/dist/addon-firefox/rules.json +1 -1
  11. package/dist/addon-mv3/background.bundle.js +11 -2
  12. package/dist/addon-mv3/content.bundle.js +510 -347
  13. package/dist/addon-mv3/manifest.json +1 -1
  14. package/dist/addon-mv3/popup.bundle.js +19 -1
  15. package/dist/addon-mv3/popup.html +14 -0
  16. package/dist/addon-mv3/rules.json +1 -1
  17. package/dist/autoconsent.cjs.js +353 -219
  18. package/dist/autoconsent.esm.js +354 -219
  19. package/dist/autoconsent.extra.cjs.js +519 -347
  20. package/dist/autoconsent.extra.esm.js +520 -347
  21. package/dist/autoconsent.playwright.js +520 -348
  22. package/lib/cmps/admiral.ts +6 -6
  23. package/lib/cmps/base.ts +43 -8
  24. package/lib/cmps/consentmanager.ts +8 -7
  25. package/lib/cmps/cookiebot.ts +4 -4
  26. package/lib/cmps/evidon.ts +2 -2
  27. package/lib/cmps/klaro.ts +8 -8
  28. package/lib/cmps/onetrust.ts +6 -6
  29. package/lib/cmps/sourcepoint-frame.ts +12 -12
  30. package/lib/cmps/tiktok.ts +3 -3
  31. package/lib/cmps/trustarc-frame.ts +11 -11
  32. package/lib/cmps/trustarc-top.ts +2 -6
  33. package/lib/dom-actions.ts +6 -6
  34. package/lib/eval-snippets.ts +6 -1
  35. package/lib/filterlist-engine.ts +2 -2
  36. package/lib/messages.ts +6 -0
  37. package/lib/types.ts +3 -2
  38. package/lib/utils.ts +49 -0
  39. package/lib/web.ts +50 -37
  40. package/package.json +2 -2
  41. package/playwright/runner.ts +1 -1
  42. package/readme.md +1 -1
  43. package/rules/autoconsent/cookie-law-info.json +16 -5
  44. package/rules/autoconsent/cookiehub.json +61 -0
  45. package/rules/autoconsent/eu-cookie-compliance.json +13 -12
  46. package/rules/compact-rules.json +1 -1
  47. package/rules/filterlist.txt +221 -202
  48. package/rules/rules.json +1 -1
  49. package/tests/{cookielawinfo.spec.ts → cookie-law-info.spec.ts} +4 -1
  50. package/tests/cookiehub.spec.ts +8 -0
  51. package/tests/eu-cookie-compliance-banner.spec.ts +1 -1
  52. package/tests-wtr/dom-actions/dom-actions.click.ts +14 -14
  53. package/tests-wtr/utils/highlight.test.ts +166 -0
package/lib/messages.ts CHANGED
@@ -7,6 +7,7 @@ export type BackgroundMessage = InitResponseMessage | EvalResponseMessage | OptO
7
7
  export type ContentScriptMessage =
8
8
  | InitMessage
9
9
  | EvalMessage
10
+ | DelayMessage
10
11
  | DetectedMessage
11
12
  | FoundMessage
12
13
  | OptOutResultMessage
@@ -32,6 +33,11 @@ export type EvalMessage = {
32
33
  snippetId?: keyof typeof snippets;
33
34
  };
34
35
 
36
+ export type DelayMessage = {
37
+ type: 'visualDelay';
38
+ timeout: number;
39
+ };
40
+
35
41
  export type DetectedMessage = {
36
42
  type: 'cmpDetected';
37
43
  cmp: string;
package/lib/types.ts CHANGED
@@ -24,7 +24,7 @@ export interface AutoCMP {
24
24
  }
25
25
 
26
26
  export interface DomActionsProvider {
27
- click(selector: ElementSelector, all: boolean): boolean;
27
+ click(selector: ElementSelector, all: boolean): Promise<boolean>;
28
28
  elementExists(selector: ElementSelector): boolean;
29
29
  elementVisible(selector: ElementSelector, check: VisibilityCheck): boolean;
30
30
  waitForElement(selector: ElementSelector, timeout?: number): Promise<boolean>;
@@ -59,6 +59,7 @@ export type Config = {
59
59
  prehideTimeout: number;
60
60
  enableFilterList: boolean;
61
61
  enableHeuristicDetection: boolean;
62
+ visualTest: boolean; // If true, the script will delay before every click action
62
63
  logs: {
63
64
  lifecycle: boolean;
64
65
  rulesteps: boolean;
@@ -97,5 +98,5 @@ export type ConsentState = {
97
98
  detectedPopups: string[]; // Names of CMP rules where `detectPopup` returned true.
98
99
  heuristicPatterns: string[]; // Matched heuristic patterns
99
100
  heuristicSnippets: string[]; // Matched heuristic snippets
100
- selfTest: boolean; // null if no self test was run, otherwise it holds the result of the self test.
101
+ selfTest: boolean | null; // null if no self test was run, otherwise it holds the result of the self test.
101
102
  };
package/lib/utils.ts CHANGED
@@ -61,6 +61,7 @@ export function isElementVisible(elem: HTMLElement): boolean {
61
61
  }
62
62
 
63
63
  export function copyObject(data: any) {
64
+ // @ts-expect-error - globalThis.structuredClone may be undefined
64
65
  if (globalThis.structuredClone) {
65
66
  return structuredClone(data);
66
67
  }
@@ -79,6 +80,7 @@ export function normalizeConfig(providedConfig: any): Config {
79
80
  isMainWorld: false,
80
81
  prehideTimeout: 2000,
81
82
  enableFilterList: false,
83
+ visualTest: false,
82
84
  logs: {
83
85
  lifecycle: false,
84
86
  rulesteps: false,
@@ -101,9 +103,56 @@ export function normalizeConfig(providedConfig: any): Config {
101
103
  }
102
104
 
103
105
  export function scheduleWhenIdle(callback: () => void, timeout = 500) {
106
+ // @ts-expect-error - globalThis.requestIdleCallback may be undefined
104
107
  if (globalThis.requestIdleCallback) {
105
108
  requestIdleCallback(callback, { timeout });
106
109
  } else {
107
110
  setTimeout(callback, 0);
108
111
  }
109
112
  }
113
+
114
+ export function highlightNode(node: HTMLElement) {
115
+ if (!node.style) return;
116
+ if (node.__oldStyles !== undefined) {
117
+ return; // already highlighted
118
+ }
119
+ if (node.hasAttribute('style')) {
120
+ node.__oldStyles = node.style.cssText;
121
+ }
122
+ node.style.animation = 'pulsate .5s infinite';
123
+ node.style.outline = 'solid red';
124
+
125
+ let styleTag = document.querySelector('style#autoconsent-debug-styles');
126
+ if (!styleTag) {
127
+ styleTag = document.createElement('style');
128
+ styleTag.id = 'autoconsent-debug-styles';
129
+ }
130
+
131
+ styleTag.textContent = `
132
+ @keyframes pulsate {
133
+ 0% {
134
+ outline-width: 8px;
135
+ outline-offset: -4px;
136
+ }
137
+ 50% {
138
+ outline-width: 4px;
139
+ outline-offset: -2px;
140
+ }
141
+ 100% {
142
+ outline-width: 8px;
143
+ outline-offset: -4px;
144
+ }
145
+ }
146
+ `;
147
+ document.head.appendChild(styleTag);
148
+ }
149
+
150
+ export function unhighlightNode(node: HTMLElement) {
151
+ if (!node.style || !node.hasAttribute('style')) return;
152
+ if (node.__oldStyles !== undefined) {
153
+ node.style.cssText = node.__oldStyles;
154
+ delete node.__oldStyles;
155
+ } else {
156
+ node.removeAttribute('style');
157
+ }
158
+ }
package/lib/web.ts CHANGED
@@ -28,8 +28,8 @@ function filterCMPs(rules: AutoCMP[], config: Config) {
28
28
  export default class AutoConsent {
29
29
  id = getRandomID();
30
30
  rules: AutoCMP[] = [];
31
- config: Config;
32
- foundCmp: AutoCMP = null;
31
+ #config?: Config;
32
+ foundCmp?: AutoCMP;
33
33
  state: ConsentState = {
34
34
  cosmeticFiltersOn: false,
35
35
  filterListReported: false,
@@ -43,12 +43,12 @@ export default class AutoConsent {
43
43
  selfTest: null,
44
44
  };
45
45
  domActions: DomActions;
46
- filtersEngine: FiltersEngine;
47
- protected sendContentMessage: MessageSender;
48
- protected cosmeticStyleSheet: CSSStyleSheet;
49
- protected focusedElement: HTMLElement = null;
46
+ filtersEngine?: FiltersEngine;
47
+ sendContentMessage: MessageSender;
48
+ protected cosmeticStyleSheet?: CSSStyleSheet;
49
+ protected focusedElement?: HTMLElement;
50
50
 
51
- constructor(sendContentMessage: MessageSender, config: Partial<Config> = null, declarativeRules: RuleBundle = null) {
51
+ constructor(sendContentMessage: MessageSender, config: Partial<Config> | null = null, declarativeRules: RuleBundle | null = null) {
52
52
  evalState.sendContentMessage = sendContentMessage;
53
53
  this.sendContentMessage = sendContentMessage;
54
54
  this.rules = [];
@@ -72,10 +72,17 @@ export default class AutoConsent {
72
72
  this.domActions = new DomActions(this);
73
73
  }
74
74
 
75
- initialize(config: Partial<Config>, declarativeRules: RuleBundle) {
75
+ get config() {
76
+ if (!this.#config) {
77
+ throw new Error('AutoConsent is not initialized yet');
78
+ }
79
+ return this.#config;
80
+ }
81
+
82
+ initialize(config: Partial<Config>, declarativeRules: RuleBundle | null) {
76
83
  const normalizedConfig = normalizeConfig(config);
77
84
  normalizedConfig.logs.lifecycle && console.log('autoconsent init', window.location.href);
78
- this.config = normalizedConfig;
85
+ this.#config = normalizedConfig;
79
86
  if (!normalizedConfig.enabled) {
80
87
  normalizedConfig.logs.lifecycle && console.log('autoconsent is disabled');
81
88
  return;
@@ -85,9 +92,9 @@ export default class AutoConsent {
85
92
  this.parseDeclarativeRules(declarativeRules);
86
93
  }
87
94
 
88
- if (config.enableFilterList) {
95
+ if (BUNDLE_FILTERLIST && config.enableFilterList) {
89
96
  try {
90
- if (BUNDLE_FILTERLIST && serializedEngine && serializedEngine.length > 0) {
97
+ if (serializedEngine && serializedEngine.length > 0) {
91
98
  this.filtersEngine = deserializeFilterList(serializedEngine);
92
99
  }
93
100
  } catch (e) {
@@ -104,7 +111,7 @@ export default class AutoConsent {
104
111
 
105
112
  this.rules = filterCMPs(this.rules, normalizedConfig);
106
113
 
107
- if (config.enablePrehide) {
114
+ if (this.shouldPrehide) {
108
115
  if (document.documentElement) {
109
116
  this.prehideElements(); // prehide as early as possible to prevent flickering
110
117
  } else {
@@ -130,6 +137,10 @@ export default class AutoConsent {
130
137
  this.updateState({ lifecycle: 'initialized' });
131
138
  }
132
139
 
140
+ get shouldPrehide() {
141
+ return this.config.enablePrehide && !this.config.visualTest;
142
+ }
143
+
133
144
  saveFocus() {
134
145
  this.focusedElement = document.activeElement as HTMLElement;
135
146
  if (this.focusedElement) {
@@ -145,7 +156,7 @@ export default class AutoConsent {
145
156
  } catch (e) {
146
157
  this.config.logs.errors && console.warn('error restoring focus', e);
147
158
  }
148
- this.focusedElement = null;
159
+ this.focusedElement = undefined;
149
160
  }
150
161
  }
151
162
 
@@ -157,9 +168,9 @@ export default class AutoConsent {
157
168
 
158
169
  parseDeclarativeRules(declarativeRules: RuleBundle) {
159
170
  if (declarativeRules.consentomatic) {
160
- Object.keys(declarativeRules.consentomatic).forEach((name) => {
161
- this.addConsentomaticCMP(name, declarativeRules.consentomatic[name]);
162
- });
171
+ for (const [name, rule] of Object.entries(declarativeRules.consentomatic)) {
172
+ this.addConsentomaticCMP(name, rule);
173
+ }
163
174
  }
164
175
 
165
176
  if (declarativeRules.autoconsent) {
@@ -202,7 +213,7 @@ export default class AutoConsent {
202
213
  this.updateState({ detectedCmps: foundCmps.map((c) => c.name) });
203
214
  if (foundCmps.length === 0) {
204
215
  logsConfig.lifecycle && console.log('no CMP found', location.href);
205
- if (this.config.enablePrehide) {
216
+ if (this.shouldPrehide) {
206
217
  this.undoPrehide();
207
218
  }
208
219
 
@@ -236,7 +247,7 @@ export default class AutoConsent {
236
247
 
237
248
  if (foundPopups.length === 0) {
238
249
  logsConfig.lifecycle && console.log('no popup found');
239
- if (this.config.enablePrehide) {
250
+ if (this.shouldPrehide) {
240
251
  this.undoPrehide();
241
252
  }
242
253
  return false;
@@ -395,11 +406,11 @@ export default class AutoConsent {
395
406
 
396
407
  async handlePopup(cmp: AutoCMP): Promise<boolean> {
397
408
  this.updateState({ lifecycle: 'openPopupDetected' });
398
- if (this.config.enablePrehide && !this.state.prehideOn) {
409
+ if (this.shouldPrehide && !this.state.prehideOn) {
399
410
  // prehide might have timeouted by this time, apply it again
400
411
  this.prehideElements();
401
412
  }
402
- if (this.state.cosmeticFiltersOn) {
413
+ if (BUNDLE_FILTERLIST && this.state.cosmeticFiltersOn) {
403
414
  // cancel cosmetic filters if we have a rule for this popup
404
415
  this.undoCosmetics();
405
416
  }
@@ -431,7 +442,7 @@ export default class AutoConsent {
431
442
  logsConfig.lifecycle && console.log(`${this.foundCmp.name}: opt out result ${optOutResult}`);
432
443
  }
433
444
 
434
- if (this.config.enablePrehide) {
445
+ if (this.shouldPrehide) {
435
446
  this.undoPrehide();
436
447
  }
437
448
 
@@ -439,15 +450,15 @@ export default class AutoConsent {
439
450
  type: 'optOutResult',
440
451
  cmp: this.foundCmp ? this.foundCmp.name : 'none',
441
452
  result: optOutResult,
442
- scheduleSelfTest: this.foundCmp && this.foundCmp.hasSelfTest,
453
+ scheduleSelfTest: Boolean(this.foundCmp && this.foundCmp.hasSelfTest),
443
454
  url: location.href,
444
455
  });
445
456
 
446
- if (optOutResult && !this.foundCmp.isIntermediate) {
457
+ if (optOutResult && this.foundCmp && !this.foundCmp.isIntermediate) {
447
458
  this.sendContentMessage({
448
459
  type: 'autoconsentDone',
449
- cmp: this.foundCmp.name,
450
- isCosmetic: this.foundCmp.isCosmetic,
460
+ cmp: this.foundCmp?.name,
461
+ isCosmetic: this.foundCmp?.isCosmetic,
451
462
  url: location.href,
452
463
  });
453
464
  this.updateState({ lifecycle: 'done' });
@@ -474,7 +485,7 @@ export default class AutoConsent {
474
485
  logsConfig.lifecycle && console.log(`${this.foundCmp.name}: opt in result ${optInResult}`);
475
486
  }
476
487
 
477
- if (this.config.enablePrehide) {
488
+ if (this.shouldPrehide) {
478
489
  this.undoPrehide();
479
490
  }
480
491
 
@@ -486,7 +497,7 @@ export default class AutoConsent {
486
497
  url: location.href,
487
498
  });
488
499
 
489
- if (optInResult && !this.foundCmp.isIntermediate) {
500
+ if (optInResult && this.foundCmp && !this.foundCmp.isIntermediate) {
490
501
  this.sendContentMessage({
491
502
  type: 'autoconsentDone',
492
503
  cmp: this.foundCmp.name,
@@ -547,12 +558,12 @@ export default class AutoConsent {
547
558
 
548
559
  const selectors = this.rules
549
560
  .filter((rule) => rule.prehideSelectors && rule.checkRunContext())
550
- .reduce((selectorList, rule) => [...selectorList, ...rule.prehideSelectors], globalHidden);
561
+ .reduce((selectorList, rule) => [...(selectorList || []), ...(rule.prehideSelectors || [])], globalHidden);
551
562
 
552
563
  this.updateState({ prehideOn: true });
553
564
  setTimeout(() => {
554
565
  // unhide things if we are still looking for a pop-up
555
- if (this.config.enablePrehide && this.state.prehideOn && !['runningOptOut', 'runningOptIn'].includes(this.state.lifecycle)) {
566
+ if (this.shouldPrehide && this.state.prehideOn && !['runningOptOut', 'runningOptIn'].includes(this.state.lifecycle)) {
556
567
  logsConfig.lifecycle && console.log('Process is taking too long, unhiding elements');
557
568
  this.undoPrehide();
558
569
  }
@@ -570,11 +581,11 @@ export default class AutoConsent {
570
581
  * @returns true if the filters were applied, false otherwise
571
582
  */
572
583
  async applyCosmeticFilters(styles?: string) {
573
- if (!this.filtersEngine) {
584
+ if (!BUNDLE_FILTERLIST || !this.filtersEngine) {
574
585
  return false;
575
586
  }
576
- const logsConfig = this.config?.logs;
577
- if (BUNDLE_FILTERLIST && !styles) {
587
+ const logsConfig = this.config.logs;
588
+ if (!styles) {
578
589
  styles = getCosmeticStylesheet(this.filtersEngine);
579
590
  }
580
591
 
@@ -606,9 +617,11 @@ export default class AutoConsent {
606
617
  }
607
618
 
608
619
  undoCosmetics() {
609
- this.updateState({ cosmeticFiltersOn: false });
610
- this.config.logs.lifecycle && console.log('[undocosmetics]', this.cosmeticStyleSheet, location.href);
611
- this.domActions.removeStyleSheet(this.cosmeticStyleSheet);
620
+ if (BUNDLE_FILTERLIST) {
621
+ this.updateState({ cosmeticFiltersOn: false });
622
+ this.config.logs.lifecycle && console.log('[undocosmetics]', this.cosmeticStyleSheet, location.href);
623
+ this.domActions.removeStyleSheet(this.cosmeticStyleSheet);
624
+ }
612
625
  }
613
626
 
614
627
  reportFilterlist() {
@@ -636,7 +649,7 @@ export default class AutoConsent {
636
649
  // this may be a false positive: sometimes filters hide unrelated elements that are not cookie pop-ups
637
650
  const cosmeticFiltersWorked = this.domActions.elementVisible(getFilterlistSelectors(cosmeticStyles), 'any');
638
651
 
639
- const logsConfig = this.config?.logs;
652
+ const logsConfig = this.config.logs;
640
653
 
641
654
  if (!cosmeticFiltersWorked) {
642
655
  logsConfig?.lifecycle && console.log("Cosmetic filters didn't work, removing them", location.href);
@@ -681,7 +694,7 @@ export default class AutoConsent {
681
694
  }
682
695
 
683
696
  async receiveMessageCallback(message: BackgroundMessage) {
684
- const logsConfig = this.config?.logs;
697
+ const logsConfig = this.#config?.logs;
685
698
  if (logsConfig?.messages) {
686
699
  console.log('received from background', message, window.location.href);
687
700
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckduckgo/autoconsent",
3
- "version": "14.0.1",
3
+ "version": "14.2.0",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
@@ -51,7 +51,7 @@
51
51
  "@esm-bundle/chai": "^4.3.4-fix.0",
52
52
  "@playwright/test": "^1.17.1",
53
53
  "@types/chai": "^5.0.0",
54
- "@types/chrome": "^0.0.322",
54
+ "@types/chrome": "^0.0.326",
55
55
  "@types/eslint": "^9.6.1",
56
56
  "@types/mocha": "^10.0.1",
57
57
  "@types/sinon": "^17.0.4",
@@ -73,7 +73,7 @@ export function generateTest(url: string, expectedCmp: string, options: TestOpti
73
73
  });
74
74
  }
75
75
 
76
- let selfTestFrame: Frame = null;
76
+ let selfTestFrame: Frame | null = null;
77
77
  async function messageCallback({ frame }: { frame: Frame }, msg: ContentScriptMessage) {
78
78
  LOG_MESSAGES.includes(msg.type) && console.log(msg);
79
79
  received.push(msg);
package/readme.md CHANGED
@@ -174,7 +174,7 @@ Returns true if the given selector matches one or more elements.
174
174
  "check": "any" | "all" | "none"
175
175
  }
176
176
  ```
177
- Returns true if elements matched by ElementSelector are currently visible on the page. If `check` is `all`, every element must be visible. If `check` is `none`, no element should be visible. Visibility check is a CSS-based heuristic.
177
+ Returns true if elements matched by ElementSelector are currently visible on the page. If `check` is `all` (default), every element must be visible. If `check` is `none`, no element should be visible. Visibility check is a CSS-based heuristic.
178
178
 
179
179
  ### Wait for element
180
180
 
@@ -1,14 +1,25 @@
1
1
  {
2
2
  "name": "cookie-law-info",
3
- "prehideSelectors": ["#cookie-law-info-bar, #cookie-law-bg"],
3
+ "prehideSelectors": ["#cookie-law-info-bar, #cookie-law-bg, .cli-popupbar-overlay"],
4
4
  "detectCmp": [{ "exists": "#cookie-law-info-bar" }, { "eval": "EVAL_COOKIE_LAW_INFO_DETECT" }],
5
- "detectPopup": [{ "visible": "#cookie-law-info-bar, #cookie-law-bg", "check": "any" }],
6
- "optIn": [{ "click": "[data-cli_action=\"accept\"]" }],
5
+ "detectPopup": [{ "visible": "#cookie-law-info-bar" }],
6
+ "optIn": [
7
+ {
8
+ "click": "[data-cli_action=\"accept\"]"
9
+ }
10
+ ],
7
11
  "optOut": [
8
- { "hide": "#cookie-law-info-bar, #cookie-law-bg" },
12
+ {
13
+ "hide": "#cookie-law-info-bar, #cookie-law-bg, .cli-popupbar-overlay"
14
+ },
9
15
  {
10
16
  "eval": "EVAL_COOKIE_LAW_INFO_0"
11
17
  }
12
18
  ],
13
- "test": [{ "cookieContains": "cookielawinfo-checkbox-non-necessary=yes", "negated": true }]
19
+ "test": [
20
+ {
21
+ "cookieContains": "cookielawinfo-checkbox-non-necessary=yes",
22
+ "negated": true
23
+ }
24
+ ]
14
25
  }
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "cookiehub",
3
+ "vendorUrl": "https://www.cookiehub.com/",
4
+ "prehideSelectors": [".ch2-container"],
5
+ "detectCmp": [
6
+ {
7
+ "exists": ".ch2-dialog"
8
+ }
9
+ ],
10
+ "detectPopup": [
11
+ {
12
+ "visible": ".ch2-dialog"
13
+ }
14
+ ],
15
+ "optIn": [
16
+ {
17
+ "waitForThenClick": ".ch2-allow-all-btn"
18
+ }
19
+ ],
20
+ "optOut": [
21
+ {
22
+ "if": { "exists": ".ch2-open-settings-btn, .ch2-open-personal-data-btn" },
23
+ "then": [
24
+ {
25
+ "click": ".ch2-open-settings-btn, .ch2-open-personal-data-btn"
26
+ },
27
+ {
28
+ "waitForVisible": ".ch2-settings"
29
+ },
30
+ {
31
+ "if": { "exists": ".ch2-deny-all-btn" },
32
+ "then": [
33
+ {
34
+ "click": ".ch2-deny-all-btn"
35
+ }
36
+ ],
37
+ "else": [
38
+ {
39
+ "click": ".ch2-settings input[type=checkbox]:not([disabled]):checked",
40
+ "all": true,
41
+ "optional": true
42
+ },
43
+ {
44
+ "click": ".ch2-save-settings-btn"
45
+ }
46
+ ]
47
+ }
48
+ ],
49
+ "else": [
50
+ {
51
+ "hide": ".ch2-container"
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "test": [
57
+ {
58
+ "cookieContains": "cookiehub="
59
+ }
60
+ ]
61
+ }
@@ -2,19 +2,20 @@
2
2
  "name": "eu-cookie-compliance-banner",
3
3
  "detectCmp": [{ "exists": "body.eu-cookie-compliance-popup-open" }],
4
4
  "detectPopup": [{ "exists": "body.eu-cookie-compliance-popup-open" }],
5
- "optIn": [{ "click": ".agree-button" }],
5
+ "optIn": [
6
+ {
7
+ "click": ".eu-cookie-compliance-banner .agree-button, .eu-cookie-compliance-banner .accept-all"
8
+ }
9
+ ],
6
10
  "optOut": [
7
11
  {
8
- "if": {
9
- "visible": ".decline-button,.eu-cookie-compliance-save-preferences-button"
10
- },
11
- "then": [
12
- {
13
- "click": ".decline-button,.eu-cookie-compliance-save-preferences-button"
14
- }
15
- ]
16
- },
17
- { "hide": ".eu-cookie-compliance-banner-info, #sliding-popup" }
12
+ "click": ".eu-cookie-compliance-banner .decline-button, .eu-cookie-compliance-banner .accept-necessary, .eu-cookie-compliance-save-preferences-button"
13
+ }
18
14
  ],
19
- "test": [{ "cookieContains": "cookie-agreed=2", "negated": true }]
15
+ "test": [
16
+ {
17
+ "cookieContains": "cookie-agreed=2",
18
+ "negated": true
19
+ }
20
+ ]
20
21
  }