MediaWiki:Common.js: Difference between revisions

From SZ
Jump to navigation Jump to search
No edit summary
Tag: Reverted
No edit summary
 
(12 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* Collapsible Sidebar for MediaWiki 1.44 (Vector + Vector-2022)
/**
* - Arrow at left of each portal header
* Collapsible Sidebar (Debug Build) - Patched for Vector & Vector 2022
* - Remembers state via localStorage
  * Logs everything to console for verification
* - No deprecated libs; RL-safe
  * - Console logs for easy debugging
  */
  */
mw.loader.using( [ 'mediawiki.util' ] ).then( function () {
  $( function () {


     // --- Config -------------------------------------------------------------
/*
     var STORAGE_KEY = 'sidebar-collapse-state:v1';
$(function () {
     // Portals to leave open on first load; you can edit this list:
     // Add toggle link
    var defaultExpanded = [ 'navigation', 'book1' ];
     var $sidebar = $('#mw-panel');
    // Force-collapse these even on first load:
     var $toggleLink = $('<a href="#" id="collapse-sidebar">Toggle Sidebar</a>')
    var defaultCollapsed = [ /* e.g. 'tools' */ ];
        .css({ display: 'block', margin: '5px', cursor: 'pointer' });


     // --- Helpers ------------------------------------------------------------
     $('#p-logo').after($toggleLink);
    function log() { /* flip to false to silence */
      if ( true && window.console && console.log ) console.log.apply( console, [ '[SidebarCollapse]' ].concat( Array.from( arguments ) ) );
    }


     function readState() {
     $toggleLink.click(function (e) {
      try {
         e.preventDefault();
         var raw = localStorage.getItem( STORAGE_KEY );
         $sidebar.toggleClass('collapsed');
         return raw ? JSON.parse( raw ) : {};
    });
      } catch (e) {
});
        log('localStorage read failed', e);
*/
        return {};
      }
    }


    function writeState(state) {
/*
      try {
        localStorage.setItem( STORAGE_KEY, JSON.stringify( state ) );
      } catch (e) {
        log('localStorage write failed', e);
      }
    }


    // Normalize an identifier for a portal/menu node
(function () {
    function portalIdFor( node ) {
  window.MWSidebarDebug = true;
      // Prefer element id like "p-navigation" -> "navigation"
      if ( node.id && node.id.indexOf('p-') === 0 ) {
        return node.id.slice(2).toLowerCase();
      }
      // Vector-2022 often has data-name="navigation"
      var dn = node.getAttribute && node.getAttribute('data-name');
      if ( dn ) return dn.toLowerCase();


      // Fallback: use heading text
  function log() {
      var heading = node.querySelector('h3, .vector-menu-heading, .portal h3');
    if (window.MWSidebarDebug) console.log('[SidebarCollapsible]', ...arguments);
      if ( heading ) {
  }
        return heading.textContent.trim().toLowerCase().replace(/\s+/g,'-');
  function warn() {
      }
    if (window.MWSidebarDebug) console.warn('[SidebarCollapsible]', ...arguments);
      // Last resort: index among siblings
  }
      return 'portal-' + ( Array.prototype.indexOf.call( node.parentNode.children, node ) );
    }


    function isExpandedClass( node ) {
  var skin = mw.config.get('skin');
      return node.classList.contains('vector-collapsible--expanded');
  log('Init start. Detected skin =', skin);
    }


    function setExpanded( node, expanded ) {
  function findPanels($root) {
      node.classList.toggle( 'vector-collapsible--expanded', !!expanded );
    // Match both Vector and Vector 2022 classes
      node.classList.toggle( 'vector-collapsible--collapsed', !expanded );
    var $panels = $root.find('#mw-panel .vector-menu-portal, #mw-panel .vector-menu.mw-portlet');
      // ARIA for accessibility
    log('Panels found:', $panels.length);
      var heading = node.querySelector('h3, .vector-menu-heading');
    return $panels;
      if ( heading ) {
  }
        heading.setAttribute( 'role', 'button' );
        heading.setAttribute( 'tabindex', '0' );
        heading.setAttribute( 'aria-expanded', String( !!expanded ) );
      }
    }


    function toggleNode( node, persist ) {
  function initOnce($root) {
      var nextState = !isExpandedClass( node );
    var $panels = findPanels($root);
      setExpanded( node, nextState );
      if ( persist ) {
        var id = portalIdFor( node );
        var state = readState();
        state[ id ] = nextState ? 1 : 0;
        writeState( state );
        log('Toggled', id, '=>', nextState ? 'open' : 'closed' );
      }
    }


     function attachToggle( node ) {
     if (!$panels.length) {
      var heading = node.querySelector('h3, .vector-menu-heading');
       warn('No sidebar panels found using selectors for Vector/Vector-2022');
      if ( !heading ) return;
       return;
 
      // Click
      heading.addEventListener( 'click', function ( e ) {
        e.preventDefault();
        toggleNode( node, true );
      } );
 
       // Keyboard (Enter/Space)
      heading.addEventListener( 'keydown', function ( e ) {
        if ( e.key === 'Enter' || e.key === ' ' ) {
          e.preventDefault();
          toggleNode( node, true );
        }
       } );
     }
     }


     // --- Locate portals for both skins -------------------------------------
     $panels.each(function (idx, el) {
    var isV22 = document.body.classList.contains('skin-vector-2022');
      var $panel = $(el);
      var id = $panel.attr('id') || ('panel#' + idx);
      var $list = $panel.find('> .vector-menu-content > .vector-menu-content-list, > .body > ul').first();


    // Vector legacy portals: div.portal under #mw-panel
      if (!$list.length) {
    var legacyPortals = Array.from( document.querySelectorAll('#mw-panel .portal') );
        warn('No list in panel:', id);
        return;
      }


    // Vector 2022 portals: nav.vector-menu-portal (exclude the main hamburger)
      var $items = $list.children('li');
    var v22Portals = Array.from( document.querySelectorAll('nav.vector-menu-portal') )
       log('Panel', id, ':', $items.length, 'top-level item(s)');
       .filter( function (el) { return !el.closest('#vector-main-menu'); } );


    var portals = isV22 ? v22Portals : legacyPortals;
      $items.each(function (i, li) {
        var $li = $(li);
        var $sub = $li.children('ul');
        if (!$sub.length) return;


    if ( portals.length === 0 ) {
        $li.addClass('collapsible-header');
      log('No portals found — are you using Vector skin?');
        if (!$li.children('.mw-collapsible-arrow').length) {
      return;
          $li.prepend($('<span class="mw-collapsible-arrow" aria-hidden="true">▶</span>'));
    }
        }
        $sub.hide();


    // --- Initialize state ---------------------------------------------------
        var headerText = ($li.find('> a').first().text() || '').trim();
    var saved = readState();
        log('Registered collapsible item', i, 'in', id, 'header=', headerText);


    portals.forEach( function ( portal ) {
        $li.off('.mwCollapsibleSidebar')
      var id = portalIdFor( portal );
          .on('click.mwCollapsibleSidebar', function (e) {
       var initial;
            if ($(e.target).closest('a').length) return;
            e.preventDefault();
            $li.toggleClass('open');
            $sub.stop(true, true).slideToggle(200);
            log('Toggled', $li.hasClass('open') ? 'open' : 'closed', ':', headerText);
          });
       });
    });
  }


      if ( saved.hasOwnProperty( id ) ) {
  mw.loader.using('mediawiki.util').then(function () {
        initial = !!saved[ id ];
    $(function () {
       } else if ( defaultCollapsed.indexOf( id ) !== -1 ) {
      console.group && console.group('[SidebarCollapsible] bootstrap');
        initial = false;
       initOnce($(document));
      } else if ( defaultExpanded.indexOf( id ) !== -1 ) {
      console.groupEnd && console.groupEnd();
        initial = true;
    });
      } else {
    mw.hook('wikipage.content').add(function ($c) {
        // Default behavior: expanded
      log('wikipage.content hook fired (re-init on dynamic content).');
        initial = true;
      initOnce($c);
      }
    });
  });


      portal.classList.add('vector-collapsible'); // cosmetic marker if you want to theme
      setExpanded( portal, initial );
      attachToggle( portal );


      log('Init portal:', id, 'expanded =', initial);
})();
    });


  } );
*/
} ).catch( function (e) {
  console.error('[SidebarCollapse] loader failed:', e);
});

Latest revision as of 15:29, 26 August 2025

/**
 * Collapsible Sidebar (Debug Build) - Patched for Vector & Vector 2022
 * Logs everything to console for verification
 */

/*
$(function () {
    // Add toggle link
    var $sidebar = $('#mw-panel');
    var $toggleLink = $('<a href="#" id="collapse-sidebar">Toggle Sidebar</a>')
        .css({ display: 'block', margin: '5px', cursor: 'pointer' });

    $('#p-logo').after($toggleLink);

    $toggleLink.click(function (e) {
        e.preventDefault();
        $sidebar.toggleClass('collapsed');
    });
});
*/

/*

(function () {
  window.MWSidebarDebug = true;

  function log() {
    if (window.MWSidebarDebug) console.log('[SidebarCollapsible]', ...arguments);
  }
  function warn() {
    if (window.MWSidebarDebug) console.warn('[SidebarCollapsible]', ...arguments);
  }

  var skin = mw.config.get('skin');
  log('Init start. Detected skin =', skin);

  function findPanels($root) {
    // Match both Vector and Vector 2022 classes
    var $panels = $root.find('#mw-panel .vector-menu-portal, #mw-panel .vector-menu.mw-portlet');
    log('Panels found:', $panels.length);
    return $panels;
  }

  function initOnce($root) {
    var $panels = findPanels($root);

    if (!$panels.length) {
      warn('No sidebar panels found using selectors for Vector/Vector-2022');
      return;
    }

    $panels.each(function (idx, el) {
      var $panel = $(el);
      var id = $panel.attr('id') || ('panel#' + idx);
      var $list = $panel.find('> .vector-menu-content > .vector-menu-content-list, > .body > ul').first();

      if (!$list.length) {
        warn('No list in panel:', id);
        return;
      }

      var $items = $list.children('li');
      log('Panel', id, ':', $items.length, 'top-level item(s)');

      $items.each(function (i, li) {
        var $li = $(li);
        var $sub = $li.children('ul');
        if (!$sub.length) return;

        $li.addClass('collapsible-header');
        if (!$li.children('.mw-collapsible-arrow').length) {
          $li.prepend($('<span class="mw-collapsible-arrow" aria-hidden="true">▶</span>'));
        }
        $sub.hide();

        var headerText = ($li.find('> a').first().text() || '').trim();
        log('Registered collapsible item', i, 'in', id, 'header=', headerText);

        $li.off('.mwCollapsibleSidebar')
          .on('click.mwCollapsibleSidebar', function (e) {
            if ($(e.target).closest('a').length) return;
            e.preventDefault();
            $li.toggleClass('open');
            $sub.stop(true, true).slideToggle(200);
            log('Toggled', $li.hasClass('open') ? 'open' : 'closed', ':', headerText);
          });
      });
    });
  }

  mw.loader.using('mediawiki.util').then(function () {
    $(function () {
      console.group && console.group('[SidebarCollapsible] bootstrap');
      initOnce($(document));
      console.groupEnd && console.groupEnd();
    });
    mw.hook('wikipage.content').add(function ($c) {
      log('wikipage.content hook fired (re-init on dynamic content).');
      initOnce($c);
    });
  });


})();

*/