MediaWiki:Common.js: Difference between revisions
Tag: Undo |
No edit summary Tag: Reverted |
||
| Line 450: | Line 450: | ||
return a; | return a; | ||
} | } | ||
function injectHeaderLinks() { | |||
if ( document.getElementById( 'gr-about-link' ) ) return; | if ( document.getElementById( 'gr-about-link' ) ) return; | ||
var headerEnd = document.querySelector( '.vector-header-end' ) || document.querySelector( '#vector-user-links' ) || document.querySelector( '.mw-header' ); | var headerEnd = document.querySelector( '.vector-header-end' ) || document.querySelector( '#vector-user-links' ) || document.querySelector( '.mw-header' ); | ||
| Line 456: | Line 456: | ||
var helpLink = makeHeaderLink( 'gr-help-link', wikiHref( 'My_wiki:Help' ), 'Help' ); | var helpLink = makeHeaderLink( 'gr-help-link', wikiHref( 'My_wiki:Help' ), 'Help' ); | ||
var aboutLink = makeHeaderLink( 'gr-about-link', wikiHref( 'My_wiki:About' ), 'About' ); | var aboutLink = makeHeaderLink( 'gr-about-link', wikiHref( 'My_wiki:About' ), 'About' ); | ||
var userName = window.mw ? mw.config.get( 'wgUserName' ) : null; | |||
var isAnon = !userName || ( window.mw && mw.config.get( 'wgUserId' ) === null ); | |||
// Build the trailing auth element (Login link for anon, dropdown for logged-in) | |||
var authEl = null; | |||
if ( isAnon ) { | |||
if ( !document.getElementById( 'gr-header-login' ) ) { | |||
authEl = makeHeaderLink( 'gr-header-login', wikiHref( 'Special:UserLogin' ), 'Login/Signup' ); | |||
} | |||
} else if ( !document.getElementById( 'gr-header-user' ) ) { | |||
authEl = buildHeaderUserDropdown( userName ); | |||
} | |||
var ul = document.querySelector( '.vector-user-links' ) || document.querySelector( '#pt-userpage' ); | var ul = document.querySelector( '.vector-user-links' ) || document.querySelector( '#pt-userpage' ); | ||
if ( ul && ul.parentNode === headerEnd ) { headerEnd.insertBefore( aboutLink, ul ); headerEnd.insertBefore( helpLink, aboutLink ); | if ( ul && ul.parentNode === headerEnd ) { | ||
else { headerEnd.appendChild( helpLink ); headerEnd.appendChild( aboutLink ); } | if ( authEl ) headerEnd.insertBefore( authEl, ul ); | ||
headerEnd.insertBefore( aboutLink, authEl || ul ); | |||
headerEnd.insertBefore( helpLink, aboutLink ); | |||
} else { | |||
headerEnd.appendChild( helpLink ); | |||
headerEnd.appendChild( aboutLink ); | |||
if ( authEl ) headerEnd.appendChild( authEl ); | |||
} | |||
} | |||
function buildHeaderUserDropdown( userName ) { | |||
var wrap = document.createElement( 'div' ); | |||
wrap.id = 'gr-header-user'; | |||
wrap.style.cssText = 'position:relative;display:inline-block;margin-right:4px;'; | |||
var trigger = document.createElement( 'button' ); | |||
trigger.id = 'gr-header-user-trigger'; | |||
trigger.type = 'button'; | |||
trigger.setAttribute( 'aria-haspopup', 'true' ); | |||
trigger.setAttribute( 'aria-expanded', 'false' ); | |||
trigger.style.cssText = [ | |||
'display:inline-flex','align-items:center','gap:5px', | |||
'color:rgba(255,255,255,0.88)','font-size:0.88em', | |||
'font-family:system-ui,sans-serif','font-weight:500', | |||
'background:transparent','border:none','cursor:pointer', | |||
'padding:4px 10px','border-radius:4px','white-space:nowrap', | |||
'transition:color 0.15s,background 0.15s' | |||
].join( ';' ); | |||
trigger.innerHTML = | |||
'<span>' + userName.replace( /</g, '<' ) + '</span>' + | |||
'<span id="gr-header-caret" style="font-size:0.8em;transition:transform 0.2s;">\u25be</span>'; | |||
trigger.addEventListener( 'mouseover', function () { this.style.color = '#fff'; this.style.background = 'rgba(255,255,255,0.12)'; } ); | |||
trigger.addEventListener( 'mouseout', function () { if ( menu.style.display === 'none' ) { this.style.color = 'rgba(255,255,255,0.88)'; this.style.background = 'transparent'; } } ); | |||
var menu = document.createElement( 'div' ); | |||
menu.id = 'gr-header-user-menu'; | |||
menu.setAttribute( 'role', 'menu' ); | |||
menu.style.cssText = [ | |||
'display:none','position:absolute','top:100%','right:0','margin-top:4px', | |||
'min-width:150px','background:#fff','border-radius:6px', | |||
'box-shadow:0 4px 16px rgba(0,0,0,0.18)','overflow:hidden','z-index:1000' | |||
].join( ';' ); | |||
var itemStyle = 'display:block;padding:10px 16px;font-size:0.9em;color:#2c1810;text-decoration:none;font-family:system-ui,sans-serif;background:#fff;'; | |||
function makeMenuItem( href, label, id ) { | |||
var a = document.createElement( 'a' ); | |||
a.href = href; a.setAttribute( 'role', 'menuitem' ); | |||
a.textContent = label; a.style.cssText = itemStyle; | |||
if ( id ) a.id = id; | |||
a.addEventListener( 'mouseover', function () { this.style.background = '#f5efe9'; } ); | |||
a.addEventListener( 'mouseout', function () { this.style.background = '#fff'; } ); | |||
return a; | |||
} | |||
menu.appendChild( makeMenuItem( wikiHref( 'Special:Profile' ), 'Profile' ) ); | |||
menu.appendChild( makeMenuItem( '#', 'Log out', 'gr-header-logout' ) ); | |||
function setOpen( open ) { | |||
menu.style.display = open ? 'block' : 'none'; | |||
trigger.setAttribute( 'aria-expanded', open ? 'true' : 'false' ); | |||
var caret = document.getElementById( 'gr-header-caret' ); | |||
if ( caret ) caret.style.transform = open ? 'rotate(180deg)' : ''; | |||
if ( open ) { trigger.style.color = '#fff'; trigger.style.background = 'rgba(255,255,255,0.12)'; } | |||
else { trigger.style.color = 'rgba(255,255,255,0.88)'; trigger.style.background = 'transparent'; } | |||
} | |||
trigger.addEventListener( 'click', function ( e ) { | |||
e.stopPropagation(); | |||
setOpen( menu.style.display === 'none' ); | |||
} ); | |||
document.addEventListener( 'click', function ( e ) { | |||
if ( !wrap.contains( e.target ) ) setOpen( false ); | |||
} ); | |||
// Logout: POST with CSRF token (same approach as the desktop dropdown) | |||
menu.querySelector( '#gr-header-logout' ).addEventListener( 'click', function ( e ) { | |||
e.preventDefault(); | |||
if ( window.mw && mw.user && mw.user.tokens ) { | |||
var t = mw.user.tokens.get( 'csrfToken' ); | |||
if ( t ) { | |||
var script = ( mw.util && mw.util.wikiScript ) ? mw.util.wikiScript() : '/index.php'; | |||
var form = document.createElement( 'form' ); | |||
form.method = 'post'; | |||
form.action = script + '?title=Special:UserLogout'; | |||
form.style.display = 'none'; | |||
form.innerHTML = | |||
'<input type="hidden" name="wpEditToken" value="' + String( t ).replace( /"/g, '"' ) + '">' + | |||
'<input type="hidden" name="title" value="Special:UserLogout">' + | |||
'<input type="hidden" name="returnto" value="Main Page">'; | |||
document.body.appendChild( form ); | |||
form.submit(); | |||
return; | |||
} | |||
} | |||
if ( window.mw && mw.Api ) { | |||
new mw.Api().postWithToken( 'csrf', { action: 'logout' } ) | |||
.done( function () { location.href = '/Main_Page'; } ) | |||
.fail( function () { location.href = '/index.php?title=Special:UserLogout'; } ); | |||
} else { | |||
location.href = '/index.php?title=Special:UserLogout'; | |||
} | |||
} ); | |||
wrap.appendChild( trigger ); | |||
wrap.appendChild( menu ); | |||
return wrap; | |||
} | } | ||
| Line 1,015: | Line 1,131: | ||
return form; | return form; | ||
} | } | ||