|
|
| Line 450: |
Line 450: |
| return a; | | return a; |
| } | | } |
| function injectHeaderLinks() { | | 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 ) { | | if ( ul && ul.parentNode === headerEnd ) { headerEnd.insertBefore( aboutLink, ul ); headerEnd.insertBefore( helpLink, aboutLink ); } |
| if ( authEl ) headerEnd.insertBefore( authEl, ul );
| | else { headerEnd.appendChild( helpLink ); headerEnd.appendChild( aboutLink ); } |
| 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;
| |
| } | | } |
| | if ( document.readyState === 'loading' ) document.addEventListener( 'DOMContentLoaded', injectHeaderLinks ); |
| | else injectHeaderLinks(); |
| | }() ); |
|
| |
|
|
| |
|