Improve popup detection with modal signals and scroll lock release - #59
Open
RomanistHere wants to merge 2 commits into
Open
RomanistHere wants to merge 2 commits into
RomanistHere wants to merge 2 commits into
Conversation
…pper scroll locks
Moderate mode:
- positionCheckTypeI reads geometry from getBoundingClientRect: viewport-true
inside transformed ancestors, where offsetTop/offsetLeft were relative to
the transformed parent and misclassified the buckets
- new mid-page bucket judged by absolute size (>=280x180) and horizontal
centering: viewport-relative area shrank on big monitors, so the same
newsletter modal was blocked on a laptop but kept on 4K as a "side button"
- language-independent modal signals (native <dialog>, aria-modal,
role=dialog/alertdialog, z-index >= 1M) decide the ambiguous buckets next
to the English word lists; a modal appearing within 2.5s of the user's own
click or keypress counts as invited and is left alone
- word matching runs on innerText instead of innerHTML - no more hits on
class names, URLs and inline JSON - with consent-manager iframes (OneTrust,
Sourcepoint, Didomi, Usercentrics...) recognized by src instead
All modes:
- showModal() dialogs are close()d before hiding: a hidden modal dialog stays
in the top layer and keeps the whole page inert (looks clean, nothing
clickable); open popovers are closed too. Delicate reopens the dialog as a
plain in-flow element instead
- scroll locks on page wrappers (#app { height: 100vh; overflow: hidden })
are released once a popup was actually hidden or moved; previously only
html/body locks were handled and some pages stayed frozen. Gated on having
acted plus the wrapper really clipping content, so app shells whose inner
panes scroll (editors, chats) are never touched
Covered by new fixtures: centered-modal (aria/z-index signals at laptop and
4K sizes), dialog-modal (page usable again after removal), dialog-after-click
(user-invoked modal kept), wrapper-scroll-lock, app-shell (negative).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NRXMzqP94iqj5tfUihF4Dw
Verification (two passes at 800ms/3000ms after each sweep): - blank-page undo: if the text that existed before the sweep is gone after it (a fixed app wrapper was hidden along with the popups), restore hidden elements biggest-first and stamp them data-popupoff-ignore so the watcher does not hide them right back; skipped on text-light pages that cannot be judged this way - escalation (moderate only): when a fixed element still owns 4/5 sampled center points (elementFromPoint, so stacking is the browser's answer), covers >=35% of the viewport, and real content exists behind it (scrollHeight evidence), remove it even though the classifier kept it. Never fires during fullscreen video, within the user-gesture window, on elements that appeared on the user's own click (tracked in a WeakSet), on hovered elements (mega menus), on video-carrying overlays, or on viewport-sized app pages (maps, editors) - timers are cleared on mode change so a stale pass can't fire into the new mode's state Performance: - checkElems batches all computed-style reads (position, display, filter) before the checks write styles: one forced recalc per sweep instead of one per hidden element - watchMutations deduplicates via Set instead of an O(n^2) spread-array - deleted unused forbWords/allowedWords/contentCheck/contentUnlockCheck and the two archived positionCheckType comment blocks (~190 lines that shipped to every page on every load) Covered by new fixtures: verify-blank (wrapper restored, real popup stays gone, restore sticks) and verify-escalation (kept wall removed once it provably blocks reading); the user-invoked dialog test now outlives both verification passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NRXMzqP94iqj5tfUihF4Dw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR enhances PopUpOFF's popup detection and removal capabilities by introducing language-independent modal recognition, user gesture tracking, and intelligent scroll lock release for page wrappers.
Key Changes
Modal Detection Improvements
hasModalSignals()function to recognize modals by markup (<dialog>,aria-modal,role="dialog") or spam z-index values (≥1,000,000) instead of relying solely on English keywordsunsolicitedModalCheck()to distinguish user-invoked popups (within 2.5s of click/keypress) from unsolicited onestrackUserGestures()to monitor user interactions (pointer/keyboard events) and spare modals opened by user actionsScroll Lock Release
unlockScrollContainers()function to detect and release scroll locks on page wrapper elements (common in SPAs and modern sites)releaseTopLayer()to properly close native<dialog>elements and popovers before hiding, preventing the page from remaining inertContent Detection Enhancements
contentEasyCheck()to examine visible text viainnerTextinstead ofinnerHTML, improving accuracygetVisibleText()helper to skip script/style tags and hidden nodesconsentIframeSelectorcovering major consent managers (OneTrust, Cookiebot, Didomi, etc.)Position Detection Refinements
offsetTop/offsetLeft/offsetHeight/offsetWidthtogetBoundingClientRect()for accurate viewport-relative measurements, especially in transformed ancestorsAdditional Updates
Implementation Details
https://claude.ai/code/session_01NRXMzqP94iqj5tfUihF4Dw