Opened 4 years ago

Closed 3 years ago

#2395 closed change (fixed)

Create a content script to implement CSS property filters functionality

Reported by: trev Assignee: sebastian
Priority: P2 Milestone:
Module: Core Keywords:
Cc: sebastian Blocked By:
Blocking: #2388, #2396, #2397, #2400 Platform: Unknown
Ready: yes Confidential: no
Tester: Unknown Verified working: no
Review URL(s):

https://codereview.adblockplus.org/29317059

Description

Background

We want to reuse code implementing CSS property filters functionality. The best approach here is a content script, it will be runnable on many platforms.

What to change

Add a content script to the adblockplus repository as chrome/content/cssProperties.js. It should implement the following functionality:

  • Request a list of rules from the background page.
  • If a non-empty list is received, search style rules matching the properties regexp.
  • Generate a list of selectors to hide by combining selector from page styles with the selector in the CSS property rule.
  • Add a stylesheet to the document with the selectors in question.
  • React to DOM modifications, recognize stylesheets being added and rerun the check for them.

Example:

  • Two CSS property rules {prefix: "foo > ", suffix: "", regexp: "background-image: .*"} and {prefix: "", suffix " > bar", regexp: "margin-left: -50px"} received from background page.
  • The page's stylesheet contains the rule .foobar {margin-left: -50px; margin-bottom: 5px; background-image: none;}
  • The content script stringifies the properties defined in this rule into "background-image: none; margin-bottom: 5px; margin-left: -50px;" (note that the properties were sorted) and applies the regular expressions from the CSS property rules to that string.
  • Since both regular expressions matched, the following combinations are generated: foo > .foobar and .foobar > bar
  • The stylesheet foo > .foobar, .foobar > bar { display: none !important; } is injected into the page.

At this stage, it is sufficient for the content script to run in Chrome, Opera and Safari.

Change History (10)

comment:1 Changed 4 years ago by trev

  • Blocking 2396 added

comment:2 Changed 4 years ago by trev

  • Blocking 2397 added

comment:3 Changed 4 years ago by sebastian

I wonder whether it actually makes sense to have this content script inject the rules directly into the DOM? Or whether we should rather make it send the the generated selectors back to the background, inserting the stylesheets with the same mechanism as used for other stylesheets on the given platfrom.

Otherwise, if this content script should/must modify the DOM directly, this would introduce code duplication and another round trip to the background page on Chrome and Safari. So in this case, I'd suggest to make this content script receive the selectors for regular element hiding filters as well, adding them to the DOM the same way. For Firefox this list would be empty of course, as other stylesheets are injected with a user stylesheet there.

comment:4 Changed 4 years ago by trev

  • Blocking 2400 added

comment:5 Changed 4 years ago by trev

The idea is of course to inject the styles by the same means it happens right now. Code duplication isn't necessary - all content scripts run in a shared namespace on Chrome and Safari, meaning that you can call updateStylesheet() from the new content script. You will merely have to consider a new source of selectors there. Note that the mechanism will be different in Firefox anyway (see #2400).

Generating selectors in the background page makes no sense given that these selectors have a client-side component. Adding a roundtrip here will only make the logic more complicated.

comment:6 Changed 4 years ago by sebastian

updateStylesheet() sends a message to the background page retriving the selectors for (regular) element hiding filters and applies them. Not quite what we need here. Sure, changes can be done to include.preload.js to reuse the functionality injecting the styles, from a different content script. But then we would still have two calls to the background page, one for regular element hiding filters, and the one done by the content script here for CSS property filters. Things could be simplified and would be more efficient if we have the content script here handle regular element hiding as well on Chrome, sending only one message to the background page.

And we could potentially reuse the code for injecting styles from Chrome for Firefox, or how would it be different there, if it's performed by the content script as well, rather then with a user stylesheet?

Last edited 4 years ago by sebastian (previous) (diff)

comment:7 Changed 4 years ago by trev

Yes, we would need to store the selectors received from the background page so we don't have to message the background page unless there was actually a change.

Firefox content scripts would have full privileges, meaning that they could add a proper user stylesheet - definitely a different code path.

comment:8 Changed 4 years ago by sebastian

  • Owner set to sebastian

comment:9 Changed 4 years ago by sebastian

  • Review URL(s) modified (diff)
  • Status changed from new to reviewing

comment:10 Changed 3 years ago by sebastian

  • Resolution set to fixed
  • Status changed from reviewing to closed
  • Tester set to Unknown
Note: See TracTickets for help on using tickets.