From 46a9c8ab8c0af211293c585471adde68f60274f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Yak=C4=B1=C5=9Ft=C4=B1r?= Date: Mon, 31 Aug 2026 20:29:13 +0300 Subject: [PATCH] feat(auth): robust hybrid YakNet SSO architecture with zero shadow DOM duplicate buttons v1.4.14 --- client.js | 162 ++++++++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 95 insertions(+), 69 deletions(-) diff --git a/client.js b/client.js index 5bc714b..5487558 100644 --- a/client.js +++ b/client.js @@ -287,78 +287,104 @@ try { var defaultLoginLink = headerRight.querySelector('my-login-link, a[href*="/login"], .login-button'); var liveWidget = headerRight.querySelector('#yaknet-header-account-widget'); - // Always hide duplicate native login link in favor of unified YakNet component - if (defaultLoginLink) { - defaultLoginLink.style.display = 'none'; - defaultLoginLink.setAttribute('aria-hidden', 'true'); - } - - if (!liveWidget) { - var widgetWrap = document.createElement('div'); - widgetWrap.id = 'yaknet-header-account-widget'; - widgetWrap.className = 'yaknet-header-widget'; - widgetWrap.style.display = 'inline-flex'; - widgetWrap.style.alignItems = 'center'; - widgetWrap.style.marginRight = '8px'; - - widgetWrap.innerHTML = - '' + - ''; - - var targetSibling = - headerRight.querySelector('my-user-menu') || - headerRight.querySelector('.user-menu') || - headerRight.querySelector('.settings-button') || - headerRight.querySelector('my-user-notifications') || - headerRight.querySelector('my-notification-bell'); - - if (targetSibling && targetSibling.parentElement === headerRight) { - headerRight.insertBefore(widgetWrap, targetSibling); - } else { - headerRight.prepend(widgetWrap); + if (isAuth) { + // 1. AUTHENTICATED: Hide native login link, Show YakNet Account Profile Menu + if (defaultLoginLink) { + defaultLoginLink.style.display = 'none'; + defaultLoginLink.setAttribute('aria-hidden', 'true'); } - } else { - var el = liveWidget.querySelector('yaknet-account'); - if (el) { - var authAttr = isAuth ? 'true' : 'false'; - if (el.getAttribute('authenticated') !== authAttr || el.getAttribute('user-name') !== displayName) { - el.setAttribute('authenticated', authAttr); - el.setAttribute('user-name', displayName); - el.setAttribute('user-email', emailStr); - if (typeof el.syncStateFromAttributes === 'function') { - el.syncStateFromAttributes(); - el.render(); + + if (!liveWidget) { + var widgetWrap = document.createElement('div'); + widgetWrap.id = 'yaknet-header-account-widget'; + widgetWrap.className = 'yaknet-header-widget'; + widgetWrap.style.display = 'inline-flex'; + widgetWrap.style.alignItems = 'center'; + widgetWrap.style.marginRight = '8px'; + + widgetWrap.innerHTML = + '' + + ''; + + var targetSibling = + headerRight.querySelector('my-user-menu') || + headerRight.querySelector('.user-menu') || + headerRight.querySelector('.settings-button') || + headerRight.querySelector('my-user-notifications') || + headerRight.querySelector('my-notification-bell'); + + if (targetSibling && targetSibling.parentElement === headerRight) { + headerRight.insertBefore(widgetWrap, targetSibling); + } else { + headerRight.prepend(widgetWrap); + } + } else { + var el = liveWidget.querySelector('yaknet-account'); + if (el) { + if (el.getAttribute('authenticated') !== 'true' || el.getAttribute('user-name') !== displayName) { + el.setAttribute('authenticated', 'true'); + el.setAttribute('user-name', displayName); + el.setAttribute('user-email', emailStr); + if (typeof el.syncStateFromAttributes === 'function') { + el.syncStateFromAttributes(); + el.render(); + } + } + + if (el.shadowRoot) { + var shadowLogoutBtn = + el.shadowRoot.getElementById('logoutBtn') || + el.shadowRoot.querySelector('.yn-logout-btn') || + el.shadowRoot.querySelector('button[title*="Çıkış"], button[aria-label*="Çıkış"]'); + if (shadowLogoutBtn && !shadowLogoutBtn.hasAttribute('data-yaktube-hooked')) { + shadowLogoutBtn.setAttribute('data-yaktube-hooked', 'true'); + shadowLogoutBtn.addEventListener( + 'click', + function (ev) { + ev.preventDefault(); + ev.stopPropagation(); + performUnifiedLogout(); + }, + true + ); + } } } + } + } else { + // 2. GUEST / NOT LOGGED IN: + // A. Physically remove any widget from DOM to guarantee zero shadow DOM duplicate buttons + if (liveWidget) { + liveWidget.remove(); + } - if (el.shadowRoot) { - var shadowLogoutBtn = - el.shadowRoot.getElementById('logoutBtn') || - el.shadowRoot.querySelector('.yn-logout-btn') || - el.shadowRoot.querySelector('button[title*="Çıkış"], button[aria-label*="Çıkış"]'); - if (shadowLogoutBtn && !shadowLogoutBtn.hasAttribute('data-yaktube-hooked')) { - shadowLogoutBtn.setAttribute('data-yaktube-hooked', 'true'); - shadowLogoutBtn.addEventListener( - 'click', - function (ev) { - ev.preventDefault(); - ev.stopPropagation(); - performUnifiedLogout(); - }, - true - ); + // B. Ensure PeerTube's native login link is the ONLY single accessible login element + if (defaultLoginLink) { + defaultLoginLink.style.display = ''; + defaultLoginLink.removeAttribute('aria-hidden'); + + var loginAnchor = + defaultLoginLink.tagName.toLowerCase() === 'a' ? defaultLoginLink : defaultLoginLink.querySelector('a'); + if (loginAnchor) { + loginAnchor.setAttribute('aria-label', 'YakNet ile Giriş Yap'); + loginAnchor.setAttribute('title', 'YakNet ile Giriş Yap'); + var spanText = loginAnchor.querySelector('span'); + if (spanText) { + spanText.textContent = 'YakNet ile Giriş Yap'; + } else { + loginAnchor.textContent = 'YakNet ile Giriş Yap'; } } } diff --git a/package.json b/package.json index 58b8ab6..dc64601 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "peertube-plugin-yaktube-ondemand", - "version": "1.4.13", + "version": "1.4.14", "description": "Accessible On-Demand YouTube Import, Live Streams, Smart Recommendations and A11y Engine for PeerTube", "main": "main.js", "library": "./main.js",