Cleaner Post-Gazette

Remove paywalls, ads, overlays, and scroll locks from the Pittsburgh Post-Gazette.

// ==UserScript==
// @name         Cleaner Post-Gazette
// @namespace    http://tampermonkey.net/
// @version      2.2
// @description  Remove paywalls, ads, overlays, and scroll locks from the Pittsburgh Post-Gazette.
// @author       crowfly
// @match        https://www.post-gazette.com/*
// @match        https://newsinteractive.post-gazette.com/*
// @icon         https://www.post-gazette.com/favicon-32x32.png
// @require      https://greasyfork.org/scripts/446257-waitforkeyelements-utility-function/code/waitForKeyElements%20utility%20function.js
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  const selectorsToRemove = [
    '.pgevoke-topads',
    '.pgevoke-grid-row[data-nativo]',
    '.pgevoke-story-topads',
    '.pgevoke-story-comments-disabled',
    '.pgevoke-story-comments',
    '.pgevoke-story-extracontent-nativo',
    '.pgevoke-civicscience',
    '.pg-bigdrawer',
    '.pg-bigdrawergradient',
    '#template-container',
  ];

  // Remove unwanted junk
  selectorsToRemove.forEach(sel => waitForKeyElements(sel, el => el.remove()));

  // Fix layout when paywall body class appears
  waitForKeyElements('body.pg-bigdraweropen .pgevoke-pagewrapper', el => {
    Object.assign(el.style, {
      height: 'auto',
      position: 'relative',
      overflowY: 'scroll',
    });
  });

  // Hide and remove transparent overlays
  waitForKeyElements('.tp-backdrop.tp-active, .tp-modal', el => {
    Object.assign(el.style, {
      display: 'none',
      opacity: '0',
    });
    el.remove();
  });

  // Auto-scroll un-locker — ensures the page stays scrollable
  const unlockScroll = () => {
    const body = document.body;
    const html = document.documentElement;

    // Restore normal scrolling
    [body, html].forEach(el => {
      if (el.style.overflow === 'hidden' || getComputedStyle(el).overflow === 'hidden') {
        el.style.overflow = 'auto';
        el.style.position = 'static';
        el.style.height = 'auto';
      }
      if (el.classList.contains('pg-bigdraweropen')) {
        el.classList.remove('pg-bigdraweropen');
      }
    });

    // Restore scroll on main wrapper if needed
    const wrapper = document.querySelector('.pgevoke-pagewrapper');
    if (wrapper) {
      wrapper.style.overflowY = 'auto';
      wrapper.style.height = 'auto';
      wrapper.style.position = 'relative';
    }

    window.scrollTo(0, window.scrollY); // re-sync scroll position
  };

  // Run immediately and periodically
  setInterval(unlockScroll, 1000);

  // Watch for new DOM mutations (for re-nuking and scroll locks)
  const observer = new MutationObserver(() => {
    selectorsToRemove.forEach(sel => {
      document.querySelectorAll(sel).forEach(el => el.remove());
    });
    unlockScroll(); // also re-check scroll state after any DOM change
  });

  observer.observe(document.body, { childList: true, subtree: true });
})();