|
|
@@ -11,41 +11,29 @@ enum RedditLoginBridgeStyle {
|
|
|
window.__reddoraLoginBridgeInstalled = true;
|
|
|
|
|
|
const LOGIN_PATTERN = /log\\s*in/i;
|
|
|
- const HEADER_SELECTORS = 'header, [role="banner"], #header, faceplate-header, nav';
|
|
|
+ const HEADER_SELECTORS = 'header, [role="banner"], #header, faceplate-header, nav, shreddit-header-action';
|
|
|
+ const CLICKABLE_SELECTORS = 'button, a, [role="button"], faceplate-tracker, faceplate-button';
|
|
|
const AUTH_MODAL_SELECTORS = [
|
|
|
'auth-flow-modal',
|
|
|
'[data-testid="login-modal"]',
|
|
|
'#credentials-login-popup',
|
|
|
+ 'shreddit-signup-drawer',
|
|
|
'faceplate-modal[slot="login"]',
|
|
|
'faceplate-modal[open]'
|
|
|
].join(', ');
|
|
|
|
|
|
+ const boundLoginTriggers = new WeakSet();
|
|
|
+
|
|
|
function nodeLabel(node) {
|
|
|
if (!(node instanceof Element)) return '';
|
|
|
return (
|
|
|
(node.textContent || '') + ' ' +
|
|
|
(node.getAttribute('aria-label') || '') + ' ' +
|
|
|
- (node.getAttribute('title') || '')
|
|
|
+ (node.getAttribute('title') || '') + ' ' +
|
|
|
+ (node.getAttribute('href') || '')
|
|
|
).trim();
|
|
|
}
|
|
|
|
|
|
- function isHeaderLoginTrigger(node) {
|
|
|
- if (!(node instanceof Element)) return false;
|
|
|
-
|
|
|
- const clickable = node.matches('button, a, [role="button"], faceplate-tracker, faceplate-button')
|
|
|
- ? node
|
|
|
- : node.closest('button, a, [role="button"], faceplate-tracker, faceplate-button');
|
|
|
- if (!clickable) return false;
|
|
|
-
|
|
|
- if (clickable.id === 'login-button') return true;
|
|
|
- if (clickable.getAttribute('data-testid') === 'login-button') return true;
|
|
|
-
|
|
|
- const label = nodeLabel(clickable);
|
|
|
- if (!LOGIN_PATTERN.test(label)) return false;
|
|
|
-
|
|
|
- return !!clickable.closest(HEADER_SELECTORS);
|
|
|
- }
|
|
|
-
|
|
|
function isLoginPage() {
|
|
|
const host = window.location.hostname.toLowerCase();
|
|
|
return (host === 'www.reddit.com' || host === 'reddit.com' || host === 'new.reddit.com')
|
|
|
@@ -69,11 +57,95 @@ enum RedditLoginBridgeStyle {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function interceptLoginEvent(event) {
|
|
|
+ if (isLoginPage()) return false;
|
|
|
+ if (eventMatchesLoginTrigger(event)) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopImmediatePropagation();
|
|
|
+ window.__reddoraCloseRedditAuthModal && window.__reddoraCloseRedditAuthModal();
|
|
|
+ requestInAppLogin();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const loginButton = document.getElementById('login-button');
|
|
|
+ if (loginButton && eventMatchesButtonBounds(event, loginButton)) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.stopImmediatePropagation();
|
|
|
+ window.__reddoraCloseRedditAuthModal && window.__reddoraCloseRedditAuthModal();
|
|
|
+ requestInAppLogin();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ function eventMatchesButtonBounds(event, button) {
|
|
|
+ if (!(button instanceof Element)) return false;
|
|
|
+ if (!(event instanceof MouseEvent) && event.type !== 'pointerdown' && event.type !== 'mousedown') {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (button.contains(event.target)) return false;
|
|
|
+
|
|
|
+ const rect = button.getBoundingClientRect();
|
|
|
+ const x = event.clientX;
|
|
|
+ const y = event.clientY;
|
|
|
+ return x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
|
|
|
+ }
|
|
|
+
|
|
|
+ function eventMatchesLoginTrigger(event) {
|
|
|
+ const path = event.composedPath ? event.composedPath() : [event.target];
|
|
|
+ for (let i = 0; i < path.length; i++) {
|
|
|
+ if (resolveLoginTrigger(path[i])) return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ function resolveLoginTrigger(node) {
|
|
|
+ if (!(node instanceof Element)) return null;
|
|
|
+
|
|
|
+ if (node.id === 'login-button') return node;
|
|
|
+ if (node.getAttribute('data-testid') === 'login-button') return node;
|
|
|
+
|
|
|
+ const clickable = node.matches(CLICKABLE_SELECTORS)
|
|
|
+ ? node
|
|
|
+ : node.closest(CLICKABLE_SELECTORS);
|
|
|
+ if (!clickable) return null;
|
|
|
+
|
|
|
+ if (clickable.id === 'login-button') return clickable;
|
|
|
+ if (clickable.getAttribute('data-testid') === 'login-button') return clickable;
|
|
|
+
|
|
|
+ const href = (clickable.getAttribute('href') || '').toLowerCase();
|
|
|
+ if (href.includes('/login')) return clickable;
|
|
|
+
|
|
|
+ const label = nodeLabel(clickable);
|
|
|
+ if (!LOGIN_PATTERN.test(label)) return null;
|
|
|
+
|
|
|
+ if (clickable.closest(HEADER_SELECTORS)) return clickable;
|
|
|
+
|
|
|
+ const rect = clickable.getBoundingClientRect();
|
|
|
+ if (rect.top >= 0 && rect.top < 96 && rect.width > 0 && rect.height > 0) {
|
|
|
+ return clickable;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ function isLoginTriggerElement(node) {
|
|
|
+ return resolveLoginTrigger(node) !== null;
|
|
|
+ }
|
|
|
+
|
|
|
function isAuthModal(element) {
|
|
|
if (!(element instanceof Element)) return false;
|
|
|
- if (element.matches('auth-flow-modal, [data-testid="login-modal"], #credentials-login-popup')) {
|
|
|
+ if (element.matches(
|
|
|
+ 'auth-flow-modal, [data-testid="login-modal"], #credentials-login-popup, shreddit-signup-drawer'
|
|
|
+ )) {
|
|
|
return true;
|
|
|
}
|
|
|
+ if (element.matches('shreddit-overlay-display')) {
|
|
|
+ return !!element.querySelector(
|
|
|
+ 'shreddit-signup-drawer, auth-flow-modal, input[type="password"]'
|
|
|
+ );
|
|
|
+ }
|
|
|
if (element.matches('faceplate-modal')) {
|
|
|
const label = nodeLabel(element);
|
|
|
return LOGIN_PATTERN.test(label) || !!element.querySelector('input[type="password"]');
|
|
|
@@ -95,6 +167,28 @@ enum RedditLoginBridgeStyle {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+ function bindDirectLoginListeners(root) {
|
|
|
+ function walk(node) {
|
|
|
+ if (!(node instanceof Element)) return;
|
|
|
+
|
|
|
+ const trigger = resolveLoginTrigger(node);
|
|
|
+ if (trigger && !boundLoginTriggers.has(trigger)) {
|
|
|
+ boundLoginTriggers.add(trigger);
|
|
|
+ ['pointerdown', 'mousedown', 'click'].forEach(function(type) {
|
|
|
+ trigger.addEventListener(type, interceptLoginEvent, true);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.shadowRoot) walk(node.shadowRoot);
|
|
|
+ const children = node.children;
|
|
|
+ for (let i = 0; i < children.length; i++) {
|
|
|
+ walk(children[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ walk(root || document.documentElement);
|
|
|
+ }
|
|
|
+
|
|
|
function installAuthModalBlocker() {
|
|
|
if (isLoginPage()) return;
|
|
|
|
|
|
@@ -105,7 +199,8 @@ enum RedditLoginBridgeStyle {
|
|
|
style.textContent = [
|
|
|
'auth-flow-modal,',
|
|
|
'[data-testid="login-modal"],',
|
|
|
- '#credentials-login-popup {',
|
|
|
+ '#credentials-login-popup,',
|
|
|
+ 'shreddit-signup-drawer {',
|
|
|
' display: none !important;',
|
|
|
' pointer-events: none !important;',
|
|
|
'}'
|
|
|
@@ -115,6 +210,8 @@ enum RedditLoginBridgeStyle {
|
|
|
|
|
|
const observer = new MutationObserver(function() {
|
|
|
if (isLoginPage()) return;
|
|
|
+ bindDirectLoginListeners(document.documentElement);
|
|
|
+
|
|
|
let foundAuthModal = false;
|
|
|
document.querySelectorAll(AUTH_MODAL_SELECTORS).forEach(function(element) {
|
|
|
if (!isAuthModal(element)) return;
|
|
|
@@ -129,21 +226,18 @@ enum RedditLoginBridgeStyle {
|
|
|
observer.observe(document.documentElement, { childList: true, subtree: true });
|
|
|
}
|
|
|
|
|
|
- document.addEventListener('click', function(event) {
|
|
|
- if (isLoginPage()) return;
|
|
|
- const path = event.composedPath();
|
|
|
- for (let i = 0; i < path.length; i++) {
|
|
|
- if (!isHeaderLoginTrigger(path[i])) continue;
|
|
|
-
|
|
|
- event.preventDefault();
|
|
|
- event.stopImmediatePropagation();
|
|
|
- window.__reddoraCloseRedditAuthModal();
|
|
|
- requestInAppLogin();
|
|
|
- return;
|
|
|
- }
|
|
|
- }, true);
|
|
|
+ ['pointerdown', 'mousedown', 'click'].forEach(function(type) {
|
|
|
+ document.addEventListener(type, interceptLoginEvent, true);
|
|
|
+ });
|
|
|
|
|
|
+ bindDirectLoginListeners(document.documentElement);
|
|
|
installAuthModalBlocker();
|
|
|
+
|
|
|
+ [250, 750, 1500, 3000].forEach(function(delay) {
|
|
|
+ setTimeout(function() {
|
|
|
+ bindDirectLoginListeners(document.documentElement);
|
|
|
+ }, delay);
|
|
|
+ });
|
|
|
})();
|
|
|
"""
|
|
|
|