Jump to content

User:Udays108/common.js: Difference between revisions

From BioMicro Center
Udays108 (talk | contribs)
No edit summary
Udays108 (talk | contribs)
No edit summary
Line 1: Line 1:
/* ============================================================
/**
  MIT BioMicro Center — MediaWiki Custom Scripts
* BioMicro Center Wiki Modern UI JavaScript
  Skin: Vector-2022  | Scope: User:USERNAME/common.js
  * Paste into: User:USERNAME/common.js
  ============================================================ */
* Promoted to: MediaWiki:Common.js (by sysop)
*/


mw.loader.using( [ 'mediawiki.util' ] ).then( function () {
( function () {
  'use strict';
'use strict';


  var WIKI = 'https://bmcwiki.mit.edu';
/* ── 1. Sidebar Toggle ──────────────────────────────────────── */
function initSidebarToggle() {
var STORAGE_KEY = 'bmc-sidebar-collapsed';
var body = document.body;


  /* Navigation — matches the mockup exactly.
// Create toggle button
    Update hrefs if your wiki uses different page titles. */
var btn = document.createElement( 'button' );
  var NAV = [
btn.id = 'bmc-sidebar-toggle';
    {
btn.setAttribute( 'aria-label', 'Toggle sidebar' );
      label: 'About',
btn.setAttribute( 'title', 'Toggle sidebar' );
      href: WIKI + '/index.php/BioMicroCenter:About'
btn.innerHTML = '☰'; // ☰ hamburger
    },
document.body.appendChild( btn );
    {
      label: 'News',
      href: WIKI + '/index.php/BioMicroCenter:News',
      children: [
        { label: 'Latest News',        href: WIKI + '/index.php/BioMicroCenter:News' },
        { label: 'Seminars',          href: WIKI + '/index.php/BioMicroCenter:Seminars' },
        { label: 'Classes & Training', href: 'https://igb.mit.edu/mini-courses', external: true }
      ]
    },
    {
      label: 'Services',
      href: WIKI + '/index.php/BioMicroCenter:Assisted_Services',
      children: [
        { label: 'Walkup',      href: WIKI + '/index.php/BioMicroCenter:Walk-up_Services' },
        { label: 'Assisted',    href: WIKI + '/index.php/BioMicroCenter:Assisted_Services' },
        { label: 'Consumables',  href: WIKI + '/index.php/BioMicroCenter:Consumables' },
        { label: 'Training',    href: 'https://igb.mit.edu/mini-courses', external: true },
        { label: 'Informatics',  href: 'https://igb.mit.edu/', external: true }
      ]
    },
    {
      label: 'Submission',
      href: WIKI + '/index.php/BioMicroCenter:Submission',
      children: [
        { group: 'MIT Users' },
        { label: 'Submit a Sample',    href: WIKI + '/index.php/BioMicroCenter:Submission' },
        { label: 'MIT Pricing',        href: WIKI + '/index.php/MIT:Pricing', external: true },
        { divider: true },
        { group: 'Non-MIT Users' },
        { label: 'External Submission', href: WIKI + '/index.php/BioMicroCenter:Submission' },
        { label: 'External Pricing',    href: WIKI + '/index.php/BioMicroCenter:Grant_Support_%26_Pricing', highlight: true }
      ]
    },
    {
      label: 'Staff',
      href: WIKI + '/index.php/BioMicroCenter:Staff'
    },
    {
      label: 'Resources',
      href: WIKI + '/index.php/BioMicroCenter:FAQ',
      children: [
        { label: 'FAQs',                   href: WIKI + '/index.php/BioMicroCenter:FAQ' },
        { label: 'Forms',                  href: WIKI + '/index.php/BioMicroCenter:Forms' },
        { label: 'Grant Support & Pricing', href: WIKI + '/index.php/BioMicroCenter:Grant_Support_%26_Pricing' },
        { label: 'Acknowledgements',        href: WIKI + '/index.php/BioMicroCenter:Acknowledgement', external: true }
      ]
    }
  ];


// Restore persisted state
if ( localStorage.getItem( STORAGE_KEY ) === '1' ) {
body.classList.add( 'sidebar-collapsed' );
}


  /* ── Helpers ── */
btn.addEventListener( 'click', function () {
  function make( tag, cls ) {
var collapsed = body.classList.toggle( 'sidebar-collapsed' );
    var n = document.createElement( tag );
localStorage.setItem( STORAGE_KEY, collapsed ? '1' : '0' );
    if ( cls ) n.className = cls;
} );
    return n;
}
  }


  function isCurrentPage( href ) {
/* ── 2. Smooth Scroll for TOC links ─────────────────────────── */
    return window.location.href.indexOf( href ) !== -1;
function initSmoothScroll() {
  }
var tocLinks = document.querySelectorAll( '#toc a, .toc a' );
tocLinks.forEach( function ( link ) {
link.addEventListener( 'click', function ( e ) {
var href = link.getAttribute( 'href' );
if ( href && href.charAt( 0 ) === '#' ) {
var target = document.getElementById( decodeURIComponent( href.slice( 1 ) ) );
if ( target ) {
e.preventDefault();
target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
// Update URL without page jump
history.pushState( null, '', href );
}
}
} );
} );
}


/* ── 3. Active Sidebar Nav Highlighting ─────────────────────── */
function highlightActiveSidebarLink() {
var currentTitle = mw.config.get( 'wgPageName' );
var sidebarLinks = document.querySelectorAll(
'#mw-panel a, .vector-column-start a'
);
sidebarLinks.forEach( function ( link ) {
var href = link.getAttribute( 'href' ) || '';
// Match by title query param or path segment
if (
href.indexOf( encodeURIComponent( currentTitle ) ) !== -1 ||
href.indexOf( currentTitle.replace( / /g, '_' ) ) !== -1
) {
var li = link.closest( 'li' );
if ( li ) {
li.classList.add( 'active' );
}
}
} );
}


  /* ── 1. Inject Topbar ── */
/* ── 4. Auto-style Plain Tables ─────────────────────────────── */
  function injectTopbar() {
function styleUnstyledTables() {
    if ( document.querySelector( '.bmc-topbar' ) ) return;
var tables = document.querySelectorAll(
    var bar = make( 'div', 'bmc-topbar' );
'.mw-parser-output table:not(.wikitable):not(.infobox):not(.navbox)'
    bar.innerHTML =
);
      '<div class="bmc-inner">' +
tables.forEach( function ( table ) {
        '<a href="mailto:biomicro@mit.edu">biomicro@mit.edu</a>' +
table.classList.add( 'wikitable' );
        '<span class="bmc-sep">|</span>617-715-4533' +
} );
        '<span class="bmc-sep">|</span>Building 68-322' +
}
      '</div>';
    document.body.insertBefore( bar, document.body.firstChild );
  }


/* ── 5. Run on page content ready ───────────────────────────── */
mw.hook( 'wikipage.content' ).add( function () {
initSidebarToggle();
initSmoothScroll();
highlightActiveSidebarLink();
styleUnstyledTables();
} );


  /* ── 2. Build Nav HTML ── */
} )();
  function buildNavList() {
    var ul = make( 'ul' );
    NAV.forEach( function ( item ) {
      var li = make( 'li' );
      var active = isCurrentPage( item.href );
 
      if ( item.children ) {
        li.className = 'bmc-dropdown' + ( active ? ' bmc-active' : '' );
        var topLink = make( 'a' );
        topLink.href = item.href;
        topLink.textContent = item.label;
        li.appendChild( topLink );
 
        var menu = make( 'div', 'bmc-dropdown-menu' );
        item.children.forEach( function ( c ) {
          if ( c.divider ) {
            menu.appendChild( make( 'div', 'bmc-divider' ) );
          } else if ( c.group ) {
            var g = make( 'div', 'bmc-group-label' );
            g.textContent = c.group;
            menu.appendChild( g );
          } else {
            var a = make( 'a' );
            a.href = c.href;
            a.textContent = c.label;
            if ( c.external ) a.setAttribute( 'target', '_blank' );
            if ( c.highlight ) { a.style.fontWeight = '600'; a.style.color = '#a31f34'; }
            menu.appendChild( a );
          }
        } );
        li.appendChild( menu );
      } else {
        li.className = active ? 'bmc-active' : '';
        var a = make( 'a' );
        a.href = item.href;
        a.textContent = item.label;
        li.appendChild( a );
      }
      ul.appendChild( li );
    } );
    return ul;
  }
 
 
  /* ── 3. Inject Header ── */
  function injectHeader() {
    if ( document.querySelector( '.bmc-header' ) ) return;
 
    var header = make( 'div', 'bmc-header' );
    var inner  = make( 'div', 'bmc-header-inner' );
 
    /* Logo */
    var logo = make( 'a', 'bmc-logo' );
    logo.href = WIKI;
    logo.innerHTML =
      '<div class="bmc-logo-mark">BMC</div>' +
      '<div class="bmc-logo-text">' +
        '<span class="bmc-logo-name">MIT BioMicro Center</span>' +
        '<span class="bmc-logo-sub">Integrated Genomics Core Facility</span>' +
      '</div>';
 
    /* Nav */
    var nav = make( 'nav', 'bmc-nav' );
    nav.appendChild( buildNavList() );
 
    /* Right side: move Vector's search + user tools here */
    var right = make( 'div', 'bmc-header-right' );
 
    /* Grab Vector's search box and user links — move into our header */
    var vectorSearch = document.querySelector( '.vector-search-box, #p-search, .mw-search-container' );
    if ( vectorSearch ) right.appendChild( vectorSearch );
 
    var vectorUser = document.querySelector( '.vector-user-links, #p-personal, .mw-portlet-personal' );
    if ( vectorUser ) right.appendChild( vectorUser );
 
    inner.appendChild( logo );
    inner.appendChild( nav );
    inner.appendChild( right );
    header.appendChild( inner );
 
    /* Insert after topbar */
    var topbar = document.querySelector( '.bmc-topbar' );
    if ( topbar ) {
      topbar.insertAdjacentElement( 'afterend', header );
    } else {
      document.body.insertBefore( header, document.body.firstChild );
    }
  }
 
 
  /* ── 4. Inject Hero Banner ── */
  function injectHero() {
    if ( document.querySelector( '.bmc-hero' ) ) return;
 
    /* Skip Special: pages and edit forms */
    var ns = mw.config.get( 'wgNamespaceNumber' );
    if ( ns < 0 ) return;
    if ( document.querySelector( '#editform' ) ) return;
 
    /* Read title from the hidden Vector h1 */
    var h1El = document.querySelector( 'h1.firstHeading, .mw-first-heading' );
    var title = h1El ? h1El.textContent.trim() : mw.config.get( 'wgTitle' );
 
    var hero = make( 'div', 'bmc-hero' );
    hero.innerHTML =
      '<div class="bmc-inner">' +
        '<div class="bmc-breadcrumb">' +
          '<a href="' + WIKI + '">Home</a>' +
          '<span class="bmc-sep">›</span>' +
          mw.html.escape( title ) +
        '</div>' +
        '<div class="bmc-hero-title">' + mw.html.escape( title ) + '</div>' +
      '</div>';
 
    /* Insert immediately before the page content container — safe, no element moved */
    var target = document.querySelector( '.mw-content-container' );
    if ( target ) {
      target.parentNode.insertBefore( hero, target );
    }
  }
 
 
  /* ── 5. Inject Footer ── */
  function injectFooter() {
    if ( document.querySelector( '.bmc-footer' ) ) return;
 
    var footer = make( 'div', 'bmc-footer' );
    footer.innerHTML =
      '<div class="bmc-footer-inner">' +
        '<div>' +
          '<h4>MIT BioMicro Center</h4>' +
          '<ul>' +
            '<li>Building 68-322</li>' +
            '<li>Cambridge, MA 02139</li>' +
            '<li><a href="mailto:biomicro@mit.edu">biomicro@mit.edu</a></li>' +
            '<li>617-715-4533</li>' +
          '</ul>' +
        '</div>' +
        '<div>' +
          '<h4>Services</h4>' +
          '<ul>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Walk-up_Services">Walk-up</a></li>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Assisted_Services">Assisted</a></li>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Consumables">Consumables</a></li>' +
            '<li><a href="https://igb.mit.edu/" target="_blank">Informatics</a></li>' +
          '</ul>' +
        '</div>' +
        '<div>' +
          '<h4>Resources</h4>' +
          '<ul>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:FAQ">FAQs</a></li>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Forms">Forms</a></li>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Grant_Support_%26_Pricing">Grant Support &amp; Pricing</a></li>' +
            '<li><a href="' + WIKI + '/index.php/BioMicroCenter:Acknowledgement">Acknowledgements</a></li>' +
          '</ul>' +
        '</div>' +
      '</div>' +
      '<div class="bmc-footer-bottom">' +
        '<span>&copy; ' + new Date().getFullYear() + ' MIT BioMicro Center</span>' +
        '<span><a href="https://accessibility.mit.edu" target="_blank">Accessibility</a></span>' +
      '</div>';
 
    document.body.appendChild( footer );
  }
 
 
  /* ── 6. Scroll Offset Fix ── */
  function fixScrollOffset() {
    var OFFSET = 116; /* topbar 28px + header 68px + buffer 20px */
    document.addEventListener( 'click', function ( e ) {
      var anchor = e.target.closest( 'a[href^="#"]' );
      if ( !anchor ) return;
      var id = anchor.getAttribute( 'href' ).slice( 1 );
      if ( !id ) return;
      var target = document.getElementById( id ) ||
                  document.querySelector( '[name="' + CSS.escape( id ) + '"]' );
      if ( !target ) return;
      e.preventDefault();
      window.scrollTo( {
        top: target.getBoundingClientRect().top + window.pageYOffset - OFFSET,
        behavior: 'smooth'
      } );
      if ( history.pushState ) history.pushState( null, null, '#' + id );
    } );
  }
 
 
  /* ── 7. Tab Panel System ── */
  function initTabs() {
    var btns  = document.querySelectorAll( '.tab-btn' );
    var panels = document.querySelectorAll( '.tab-panel' );
    if ( !btns.length ) return;
 
    if ( !document.querySelector( '.tab-btn.active' ) ) btns[ 0 ].classList.add( 'active' );
    if ( !document.querySelector( '.tab-panel.active' ) && panels[ 0 ] ) panels[ 0 ].classList.add( 'active' );
 
    btns.forEach( function ( btn ) {
      btn.addEventListener( 'click', function () {
        btns.forEach(  function ( t ) { t.classList.remove( 'active' ); } );
        panels.forEach( function ( p ) { p.classList.remove( 'active' ); } );
        btn.classList.add( 'active' );
        var panel = document.getElementById( 'tab-' + btn.dataset.tab );
        if ( panel ) panel.classList.add( 'active' );
        var wrap = document.querySelector( '.tab-bar-wrap' );
        if ( wrap ) window.scrollTo( { top: wrap.getBoundingClientRect().top + window.pageYOffset - 96, behavior: 'smooth' } );
      } );
    } );
  }
 
 
  /* ── Run ── */
  injectTopbar();
  injectHeader();
  injectHero();
  injectFooter();
  fixScrollOffset();
  initTabs();
 
} );

Revision as of 21:32, 8 May 2026

/**
 * BioMicro Center Wiki — Modern UI JavaScript
 * Paste into: User:USERNAME/common.js
 * Promoted to: MediaWiki:Common.js (by sysop)
 */

( function () {
	'use strict';

	/* ── 1. Sidebar Toggle ──────────────────────────────────────── */
	function initSidebarToggle() {
		var STORAGE_KEY = 'bmc-sidebar-collapsed';
		var body = document.body;

		// Create toggle button
		var btn = document.createElement( 'button' );
		btn.id = 'bmc-sidebar-toggle';
		btn.setAttribute( 'aria-label', 'Toggle sidebar' );
		btn.setAttribute( 'title', 'Toggle sidebar' );
		btn.innerHTML = '&#9776;'; // ☰ hamburger
		document.body.appendChild( btn );

		// Restore persisted state
		if ( localStorage.getItem( STORAGE_KEY ) === '1' ) {
			body.classList.add( 'sidebar-collapsed' );
		}

		btn.addEventListener( 'click', function () {
			var collapsed = body.classList.toggle( 'sidebar-collapsed' );
			localStorage.setItem( STORAGE_KEY, collapsed ? '1' : '0' );
		} );
	}

	/* ── 2. Smooth Scroll for TOC links ─────────────────────────── */
	function initSmoothScroll() {
		var tocLinks = document.querySelectorAll( '#toc a, .toc a' );
		tocLinks.forEach( function ( link ) {
			link.addEventListener( 'click', function ( e ) {
				var href = link.getAttribute( 'href' );
				if ( href && href.charAt( 0 ) === '#' ) {
					var target = document.getElementById( decodeURIComponent( href.slice( 1 ) ) );
					if ( target ) {
						e.preventDefault();
						target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
						// Update URL without page jump
						history.pushState( null, '', href );
					}
				}
			} );
		} );
	}

	/* ── 3. Active Sidebar Nav Highlighting ─────────────────────── */
	function highlightActiveSidebarLink() {
		var currentTitle = mw.config.get( 'wgPageName' );
		var sidebarLinks = document.querySelectorAll(
			'#mw-panel a, .vector-column-start a'
		);
		sidebarLinks.forEach( function ( link ) {
			var href = link.getAttribute( 'href' ) || '';
			// Match by title query param or path segment
			if (
				href.indexOf( encodeURIComponent( currentTitle ) ) !== -1 ||
				href.indexOf( currentTitle.replace( / /g, '_' ) ) !== -1
			) {
				var li = link.closest( 'li' );
				if ( li ) {
					li.classList.add( 'active' );
				}
			}
		} );
	}

	/* ── 4. Auto-style Plain Tables ─────────────────────────────── */
	function styleUnstyledTables() {
		var tables = document.querySelectorAll(
			'.mw-parser-output table:not(.wikitable):not(.infobox):not(.navbox)'
		);
		tables.forEach( function ( table ) {
			table.classList.add( 'wikitable' );
		} );
	}

	/* ── 5. Run on page content ready ───────────────────────────── */
	mw.hook( 'wikipage.content' ).add( function () {
		initSidebarToggle();
		initSmoothScroll();
		highlightActiveSidebarLink();
		styleUnstyledTables();
	} );

} )();