Browser extension to hide view-reducing screen junk from websites.

bannerbanner/src/ content_script.js
103 lines
2.8 KiB

  1. import browser from 'webextension-polyfill'
  2. import throttle from 'lodash/throttle'
  3. import { onEnabledChange, isEnabled } from './perOrigin'
  4. function hideBanners() {
  5. const revertSteps = []
  6. /* Hide all elements with position:fixed */
  7. const fixedElements = Array.from(document.querySelectorAll('*'))
  8. .filter(el => (
  9. getComputedStyle(el).position === 'fixed'
  10. && el.style.opacity !== '0' // ignore if we already hid this one
  11. ))
  12. fixedElements.forEach(el => {
  13. const originalVisibility = el.style.visibility
  14. const originalOpacity = el.style.opacity
  15. const originalTransition = el.style.transition
  16. el.style.transition = 'opacity 1s'
  17. el.style.opacity = '0'
  18. const hiderTimeoutId = window.setTimeout(() => {
  19. el.style.visibility = 'hidden'
  20. }, 1000)
  21. revertSteps.push(() => {
  22. window.clearTimeout(hiderTimeoutId)
  23. const reverterTimeoutId = window.setTimeout(() => {
  24. el.style.transition = originalTransition
  25. }, 1000)
  26. el.style.visibility = originalVisibility
  27. el.style.opacity = originalOpacity
  28. })
  29. })
  30. /* Stop position:sticky elements from sticking. */
  31. const stickyElements = Array.from(document.querySelectorAll('*'))
  32. .filter(el => getComputedStyle(el).position === 'sticky')
  33. stickyElements.forEach(el => {
  34. const originalPosition = el.style.position
  35. el.style.position = 'relative'
  36. revertSteps.push(() => {
  37. el.style.position = originalPosition
  38. })
  39. })
  40. return revertSteps
  41. }
  42. async function main() {
  43. let revertSteps = []
  44. // XXX We read the location only once, but it may be changed by page scripts.
  45. // Fortunately we only need the origin, which should remain the same.
  46. const url = window.location.href
  47. function run() {
  48. if (enabled && scrolledDown) {
  49. // Hide everything that looks annoying. Remember the steps to revert this.
  50. revertSteps = hideBanners().concat(revertSteps)
  51. } else {
  52. // Unhide everything we have hidden.
  53. if (revertSteps.length > 0) {
  54. revertSteps.forEach(step => step())
  55. revertSteps = []
  56. }
  57. }
  58. }
  59. // Run whenever the extension is enabled/disabled for this domain.
  60. let enabled = await isEnabled(url)
  61. onEnabledChange(url, newValue => { enabled = newValue; run() })
  62. // Run whenever crossing the scroll threshold.
  63. let scrolledDown = window.scrollY > 20
  64. window.addEventListener('scroll', () => {
  65. // We add a hysteresis of 20px.
  66. if (window.scrollY > 20 && !scrolledDown) {
  67. scrolledDown = true
  68. run()
  69. } else if (window.scrollY <= 0 && scrolledDown) {
  70. scrolledDown = false
  71. run()
  72. }
  73. })
  74. // Run on any page mutation, but at most once per second.
  75. const observer = new MutationObserver(throttle(() => run(), 1000))
  76. observer.observe(document, {
  77. subtree: true,
  78. childList: true,
  79. attributes: true,
  80. })
  81. // Run once now.
  82. run()
  83. }
  84. main()