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 3: Line 3:
  * Paste into: User:USERNAME/common.js
  * Paste into: User:USERNAME/common.js
  * Promoted to: MediaWiki:Common.js (by sysop)
  * Promoted to: MediaWiki:Common.js (by sysop)
*
* Injects: topbar, page-hero, horizontal nav w/ dropdowns.
* Enhances: TOC styling, smooth scroll, table auto-class.
  */
  */


Line 8: Line 11:
'use strict';
'use strict';


/* ── 1. Sidebar Toggle ──────────────────────────────────────── */
/* ── Nav definition (mirrors about.html) ───────────────────── */
function initSidebarToggle() {
var NAV_ITEMS = [
var STORAGE_KEY = 'bmc-sidebar-collapsed';
{
var body = document.body;
label: 'About',
href: 'http://biomicro.mit.edu/about.html',
match: [ 'BioMicroCenter', 'About' ]
},
{
label: 'News',
href: 'http://biomicro.mit.edu/news.html',
match: [ 'News' ],
dropdown: [
{ label: 'Latest News', href: 'http://biomicro.mit.edu/news.html' },
{ label: 'Seminars', href: 'http://biomicro.mit.edu/seminars.html' },
{ label: 'Classes & Training', href: 'https://igb.mit.edu/mini-courses', external: true }
]
},
{
label: 'Services',
href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services',
match: [ 'Assisted_Services', 'Walkup', 'Services' ],
dropdown: [
{ label: 'Walkup', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation' },
{ label: 'Assisted', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
{ label: 'Consumables', href: 'http://biomicro.mit.edu/consumables.html' },
{ label: 'Training', href: 'https://igb.mit.edu/mini-courses', external: true },
{ label: 'Informatics', href: 'https://igb.mit.edu/', external: true }
]
},
{
label: 'Submission',
href: 'http://biomicro.mit.edu/submit.html',
match: [ 'Submission', 'Submit' ],
dropdown: [
{ groupLabel: 'MIT Users' },
{ label: 'Submit a Sample', href: 'http://biomicro.mit.edu/submit.html' },
{ label: 'MIT Pricing', href: 'https://bmcwiki.mit.edu/index.php/MIT:Pricing' },
{ divider: true },
{ groupLabel: 'Non-MIT Users' },
{ label: 'External Submission', href: 'http://biomicro.mit.edu/submit.html' },
{ label: 'External Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' }
]
},
{
label: 'Staff',
href: 'http://biomicro.mit.edu/staff.html',
match: [ 'Staff' ]
},
{
label: 'Resources',
href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ',
match: [ 'FAQ', 'Resources', 'Forms', 'Acknowledgement' ],
dropdown: [
{ label: 'FAQs', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ' },
{ label: 'Forms', href: 'http://biomicro.mit.edu/forms.html' },
{ label: 'Grant Support & Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' },
{ label: 'Acknowledgements', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement' }
]
}
];
 
/* ── Helper: create element with attrs & children ──────────── */
function el( tag, attrs, children ) {
var node = document.createElement( tag );
Object.keys( attrs || {} ).forEach( function ( k ) {
if ( k === 'className' ) {
node.className = attrs[ k ];
} else if ( k === 'textContent' ) {
node.textContent = attrs[ k ];
} else if ( k === 'innerHTML' ) {
node.innerHTML = attrs[ k ];
} else {
node.setAttribute( k, attrs[ k ] );
}
} );
( children || [] ).forEach( function ( c ) {
if ( c ) node.appendChild( c );
} );
return node;
}


// Create toggle button
/* ── 1. Inject Topbar ───────────────────────────────────────── */
var btn = document.createElement( 'button' );
function injectTopbar() {
btn.id = 'bmc-sidebar-toggle';
var topbar = el( 'div', { className: 'bmc-topbar' }, [
btn.setAttribute( 'aria-label', 'Toggle sidebar' );
el( 'div', { className: 'bmc-topbar-inner' }, [
btn.setAttribute( 'title', 'Toggle sidebar' );
el( 'a', { href: 'mailto:biomicro@mit.edu', textContent: 'biomicro@mit.edu' } ),
btn.innerHTML = '☰'; // ☰ hamburger
el( 'span', { textContent: '|' } ),
document.body.appendChild( btn );
document.createTextNode( '617-715-4533' ),
el( 'span', { textContent: '|' } ),
document.createTextNode( 'Building 68-322' )
] )
] );


// Restore persisted state
// Insert before the MediaWiki header element
if ( localStorage.getItem( STORAGE_KEY ) === '1' ) {
var mwHead = document.getElementById( 'mw-head' ) ||
body.classList.add( 'sidebar-collapsed' );
document.querySelector( '.vector-header' );
if ( mwHead && mwHead.parentNode ) {
mwHead.parentNode.insertBefore( topbar, mwHead );
} else {
document.body.insertBefore( topbar, document.body.firstChild );
}
}


btn.addEventListener( 'click', function () {
// Adjust sticky header top offset to account for topbar height
var collapsed = body.classList.toggle( 'sidebar-collapsed' );
var topbarH = topbar.offsetHeight;
localStorage.setItem( STORAGE_KEY, collapsed ? '1' : '0' );
var style = document.createElement( 'style' );
style.textContent =
'#mw-head, .vector-header, .vector-header-container { top: ' + topbarH + 'px !important; }' +
'.bmc-page-hero { margin-top: 0; }';
document.head.appendChild( style );
}
 
/* ── 2. Inject Horizontal Nav ───────────────────────────────── */
function buildNavItem( item, currentPage ) {
var li = document.createElement( 'li' );
 
// Check if this nav item is active
var isActive = ( item.match || [] ).some( function ( m ) {
return currentPage.indexOf( m ) !== -1;
} );
} );
}
if ( isActive ) li.classList.add( 'bmc-active' );
 
var link = el( 'a', { href: item.href, textContent: item.label } );
li.appendChild( link );
 
if ( item.dropdown && item.dropdown.length ) {
li.classList.add( 'bmc-dropdown' );
var menu = el( 'div', { className: 'bmc-dropdown-menu' } );


/* ── 2. Smooth Scroll for TOC links ─────────────────────────── */
item.dropdown.forEach( function ( d ) {
function initSmoothScroll() {
if ( d.divider ) {
var tocLinks = document.querySelectorAll( '#toc a, .toc a' );
menu.appendChild( el( 'div', { className: 'bmc-divider' } ) );
tocLinks.forEach( function ( link ) {
} else if ( d.groupLabel ) {
link.addEventListener( 'click', function ( e ) {
menu.appendChild( el( 'div', {
var href = link.getAttribute( 'href' );
className: 'bmc-group-label',
if ( href && href.charAt( 0 ) === '#' ) {
textContent: d.groupLabel
var target = document.getElementById( decodeURIComponent( href.slice( 1 ) ) );
} ) );
if ( target ) {
} else {
e.preventDefault();
var a = el( 'a', { href: d.href, textContent: d.label } );
target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
if ( d.external ) a.setAttribute( 'target', '_blank' );
// Update URL without page jump
menu.appendChild( a );
history.pushState( null, '', href );
}
}
}
} );
} );
li.appendChild( menu );
}
return li;
}
function injectHorizontalNav() {
var currentPage = mw.config.get( 'wgPageName' ) || '';
var ul = document.createElement( 'ul' );
NAV_ITEMS.forEach( function ( item ) {
ul.appendChild( buildNavItem( item, currentPage ) );
} );
} );
var nav = el( 'nav', { className: 'bmc-hnav' }, [ ul ] );
// Find or create the header inner wrapper
var mwHead = document.getElementById( 'mw-head' ) ||
document.querySelector( '.vector-header' );
if ( !mwHead ) return;
// Find or create a flex inner container
var inner = mwHead.querySelector( '.bmc-header-inner' );
if ( !inner ) {
inner = el( 'div', { className: 'bmc-header-inner' } );
// Move existing header children into inner (except topbar)
Array.from( mwHead.childNodes ).forEach( function ( child ) {
inner.appendChild( child );
} );
mwHead.appendChild( inner );
}
// Build logo
var logoLink = el( 'a', {
href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter',
className: 'bmc-logo'
}, [
el( 'div', { className: 'bmc-logo-mark', textContent: 'BMC' } ),
el( 'div', { className: 'bmc-logo-text' }, [
el( 'span', { className: 'bmc-logo-name', textContent: 'MIT BioMicro Center' } ),
el( 'span', { className: 'bmc-logo-sub', textContent: 'Integrated Genomics Core Facility' } )
] )
] );
// Clear inner and rebuild with logo + nav
inner.innerHTML = '';
inner.appendChild( logoLink );
inner.appendChild( nav );
}
}


/* ── 3. Active Sidebar Nav Highlighting ─────────────────────── */
/* ── 3. Inject Page Hero ────────────────────────────────────── */
function highlightActiveSidebarLink() {
function injectPageHero() {
var currentTitle = mw.config.get( 'wgPageName' );
// Get page title from MediaWiki's firstHeading
var sidebarLinks = document.querySelectorAll(
var titleEl = document.getElementById( 'firstHeading' ) ||
'#mw-panel a, .vector-column-start a'
document.querySelector( '.mw-first-heading' );
);
var titleText = titleEl ? titleEl.textContent.trim() : mw.config.get( 'wgTitle' );
sidebarLinks.forEach( function ( link ) {
 
var href = link.getAttribute( 'href' ) || '';
// Build breadcrumb
// Match by title query param or path segment
var crumb = el( 'div', { className: 'bmc-breadcrumb' }, [
if (
el( 'a', { href: 'http://biomicro.mit.edu', textContent: 'Home' } ),
href.indexOf( encodeURIComponent( currentTitle ) ) !== -1 ||
el( 'span', { textContent: '›' } ),
href.indexOf( currentTitle.replace( / /g, '_' ) ) !== -1
document.createTextNode( titleText )
) {
] );
var li = link.closest( 'li' );
 
if ( li ) {
var heroH1 = el( 'h1', { textContent: titleText } );
li.classList.add( 'active' );
 
}
var heroInner = el( 'div', { className: 'bmc-hero-inner' }, [ crumb, heroH1 ] );
var hero = el( 'div', { className: 'bmc-page-hero' }, [ heroInner ] );
 
// Insert hero between header and content
var mwHead = document.getElementById( 'mw-head' ) ||
document.querySelector( '.vector-header' );
var content = document.getElementById( 'content' ) ||
document.querySelector( '.mw-body' ) ||
document.querySelector( '.vector-body' );
 
if ( mwHead && mwHead.parentNode ) {
var ref = mwHead.nextSibling;
mwHead.parentNode.insertBefore( hero, ref );
} else if ( content && content.parentNode ) {
content.parentNode.insertBefore( hero, content );
}
}
 
/* ── 4. Rewrite Footer ──────────────────────────────────────── */
function rewriteFooter() {
var footer = document.getElementById( 'footer' ) ||
document.querySelector( '.mw-footer' );
if ( !footer ) return;
 
var inner = el( 'div', { className: 'bmc-footer-inner' }, [
// Col 1: address
el( 'div', {}, [
el( 'h4', { textContent: 'MIT BioMicro Center' } ),
( function () {
var ul = document.createElement( 'ul' );
[ 'Building 68-322', 'Cambridge, MA 02139' ].forEach( function ( t ) {
ul.appendChild( el( 'li', { textContent: t } ) );
} );
var emailLi = document.createElement( 'li' );
emailLi.appendChild( el( 'a', {
href: 'mailto:biomicro@mit.edu',
textContent: 'biomicro@mit.edu'
} ) );
ul.appendChild( emailLi );
ul.appendChild( el( 'li', { textContent: '617-715-4533' } ) );
return ul;
} )()
] ),
// Col 2: services
el( 'div', {}, [
el( 'h4', { textContent: 'Services' } ),
( function () {
var ul = document.createElement( 'ul' );
[
{ label: 'Bulk Sequencing', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
{ label: 'Single Cell', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
{ label: 'Spatial Genomics', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation' },
{ label: 'Informatics', href: 'https://igb.mit.edu/' }
].forEach( function ( item ) {
var li = document.createElement( 'li' );
li.appendChild( el( 'a', { href: item.href, textContent: item.label } ) );
ul.appendChild( li );
} );
return ul;
} )()
] ),
// Col 3: resources
el( 'div', {}, [
el( 'h4', { textContent: 'Resources' } ),
( function () {
var ul = document.createElement( 'ul' );
[
{ label: 'FAQs', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ' },
{ label: 'Forms', href: 'http://biomicro.mit.edu/forms.html' },
{ label: 'Grant Support & Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' },
{ label: 'Acknowledgements', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement' }
].forEach( function ( item ) {
var li = document.createElement( 'li' );
li.appendChild( el( 'a', { href: item.href, textContent: item.label } ) );
ul.appendChild( li );
} );
return ul;
} )()
] )
] );
 
var bottom = el( 'div', { className: 'bmc-footer-bottom' }, [
el( 'span', { textContent: '© ' + new Date().getFullYear() + ' MIT BioMicro Center' } ),
el( 'span', {}, [
el( 'a', {
href: 'https://accessibility.mit.edu',
target: '_blank',
textContent: 'Accessibility'
} )
] )
] );
 
footer.innerHTML = '';
footer.appendChild( inner );
footer.appendChild( bottom );
}
 
/* ── 5. Smooth Scroll ───────────────────────────────────────── */
function initSmoothScroll() {
var content = document.querySelector( '.mw-parser-output' );
if ( !content ) return;
content.addEventListener( 'click', function ( e ) {
var a = e.target.closest( 'a[href^="#"]' );
if ( !a ) return;
var target = document.getElementById(
decodeURIComponent( a.getAttribute( 'href' ).slice( 1 ) )
);
if ( target ) {
e.preventDefault();
target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
history.pushState( null, '', a.getAttribute( 'href' ) );
}
}
} );
} );
}
}


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


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


} )();
} )();

Revision as of 21:53, 8 May 2026

/**
 * BioMicro Center Wiki — Modern UI JavaScript
 * Paste into: User:USERNAME/common.js
 * Promoted to: MediaWiki:Common.js (by sysop)
 *
 * Injects: topbar, page-hero, horizontal nav w/ dropdowns.
 * Enhances: TOC styling, smooth scroll, table auto-class.
 */

( function () {
	'use strict';

	/* ── Nav definition (mirrors about.html) ───────────────────── */
	var NAV_ITEMS = [
		{
			label: 'About',
			href: 'http://biomicro.mit.edu/about.html',
			match: [ 'BioMicroCenter', 'About' ]
		},
		{
			label: 'News',
			href: 'http://biomicro.mit.edu/news.html',
			match: [ 'News' ],
			dropdown: [
				{ label: 'Latest News', href: 'http://biomicro.mit.edu/news.html' },
				{ label: 'Seminars', href: 'http://biomicro.mit.edu/seminars.html' },
				{ label: 'Classes & Training', href: 'https://igb.mit.edu/mini-courses', external: true }
			]
		},
		{
			label: 'Services',
			href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services',
			match: [ 'Assisted_Services', 'Walkup', 'Services' ],
			dropdown: [
				{ label: 'Walkup', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation' },
				{ label: 'Assisted', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
				{ label: 'Consumables', href: 'http://biomicro.mit.edu/consumables.html' },
				{ label: 'Training', href: 'https://igb.mit.edu/mini-courses', external: true },
				{ label: 'Informatics', href: 'https://igb.mit.edu/', external: true }
			]
		},
		{
			label: 'Submission',
			href: 'http://biomicro.mit.edu/submit.html',
			match: [ 'Submission', 'Submit' ],
			dropdown: [
				{ groupLabel: 'MIT Users' },
				{ label: 'Submit a Sample', href: 'http://biomicro.mit.edu/submit.html' },
				{ label: 'MIT Pricing', href: 'https://bmcwiki.mit.edu/index.php/MIT:Pricing' },
				{ divider: true },
				{ groupLabel: 'Non-MIT Users' },
				{ label: 'External Submission', href: 'http://biomicro.mit.edu/submit.html' },
				{ label: 'External Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' }
			]
		},
		{
			label: 'Staff',
			href: 'http://biomicro.mit.edu/staff.html',
			match: [ 'Staff' ]
		},
		{
			label: 'Resources',
			href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ',
			match: [ 'FAQ', 'Resources', 'Forms', 'Acknowledgement' ],
			dropdown: [
				{ label: 'FAQs', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ' },
				{ label: 'Forms', href: 'http://biomicro.mit.edu/forms.html' },
				{ label: 'Grant Support & Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' },
				{ label: 'Acknowledgements', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement' }
			]
		}
	];

	/* ── Helper: create element with attrs & children ──────────── */
	function el( tag, attrs, children ) {
		var node = document.createElement( tag );
		Object.keys( attrs || {} ).forEach( function ( k ) {
			if ( k === 'className' ) {
				node.className = attrs[ k ];
			} else if ( k === 'textContent' ) {
				node.textContent = attrs[ k ];
			} else if ( k === 'innerHTML' ) {
				node.innerHTML = attrs[ k ];
			} else {
				node.setAttribute( k, attrs[ k ] );
			}
		} );
		( children || [] ).forEach( function ( c ) {
			if ( c ) node.appendChild( c );
		} );
		return node;
	}

	/* ── 1. Inject Topbar ───────────────────────────────────────── */
	function injectTopbar() {
		var topbar = el( 'div', { className: 'bmc-topbar' }, [
			el( 'div', { className: 'bmc-topbar-inner' }, [
				el( 'a', { href: 'mailto:biomicro@mit.edu', textContent: 'biomicro@mit.edu' } ),
				el( 'span', { textContent: '|' } ),
				document.createTextNode( '617-715-4533' ),
				el( 'span', { textContent: '|' } ),
				document.createTextNode( 'Building 68-322' )
			] )
		] );

		// Insert before the MediaWiki header element
		var mwHead = document.getElementById( 'mw-head' ) ||
			document.querySelector( '.vector-header' );
		if ( mwHead && mwHead.parentNode ) {
			mwHead.parentNode.insertBefore( topbar, mwHead );
		} else {
			document.body.insertBefore( topbar, document.body.firstChild );
		}

		// Adjust sticky header top offset to account for topbar height
		var topbarH = topbar.offsetHeight;
		var style = document.createElement( 'style' );
		style.textContent =
			'#mw-head, .vector-header, .vector-header-container { top: ' + topbarH + 'px !important; }' +
			'.bmc-page-hero { margin-top: 0; }';
		document.head.appendChild( style );
	}

	/* ── 2. Inject Horizontal Nav ───────────────────────────────── */
	function buildNavItem( item, currentPage ) {
		var li = document.createElement( 'li' );

		// Check if this nav item is active
		var isActive = ( item.match || [] ).some( function ( m ) {
			return currentPage.indexOf( m ) !== -1;
		} );
		if ( isActive ) li.classList.add( 'bmc-active' );

		var link = el( 'a', { href: item.href, textContent: item.label } );
		li.appendChild( link );

		if ( item.dropdown && item.dropdown.length ) {
			li.classList.add( 'bmc-dropdown' );
			var menu = el( 'div', { className: 'bmc-dropdown-menu' } );

			item.dropdown.forEach( function ( d ) {
				if ( d.divider ) {
					menu.appendChild( el( 'div', { className: 'bmc-divider' } ) );
				} else if ( d.groupLabel ) {
					menu.appendChild( el( 'div', {
						className: 'bmc-group-label',
						textContent: d.groupLabel
					} ) );
				} else {
					var a = el( 'a', { href: d.href, textContent: d.label } );
					if ( d.external ) a.setAttribute( 'target', '_blank' );
					menu.appendChild( a );
				}
			} );

			li.appendChild( menu );
		}

		return li;
	}

	function injectHorizontalNav() {
		var currentPage = mw.config.get( 'wgPageName' ) || '';

		var ul = document.createElement( 'ul' );
		NAV_ITEMS.forEach( function ( item ) {
			ul.appendChild( buildNavItem( item, currentPage ) );
		} );

		var nav = el( 'nav', { className: 'bmc-hnav' }, [ ul ] );

		// Find or create the header inner wrapper
		var mwHead = document.getElementById( 'mw-head' ) ||
			document.querySelector( '.vector-header' );
		if ( !mwHead ) return;

		// Find or create a flex inner container
		var inner = mwHead.querySelector( '.bmc-header-inner' );
		if ( !inner ) {
			inner = el( 'div', { className: 'bmc-header-inner' } );
			// Move existing header children into inner (except topbar)
			Array.from( mwHead.childNodes ).forEach( function ( child ) {
				inner.appendChild( child );
			} );
			mwHead.appendChild( inner );
		}

		// Build logo
		var logoLink = el( 'a', {
			href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter',
			className: 'bmc-logo'
		}, [
			el( 'div', { className: 'bmc-logo-mark', textContent: 'BMC' } ),
			el( 'div', { className: 'bmc-logo-text' }, [
				el( 'span', { className: 'bmc-logo-name', textContent: 'MIT BioMicro Center' } ),
				el( 'span', { className: 'bmc-logo-sub', textContent: 'Integrated Genomics Core Facility' } )
			] )
		] );

		// Clear inner and rebuild with logo + nav
		inner.innerHTML = '';
		inner.appendChild( logoLink );
		inner.appendChild( nav );
	}

	/* ── 3. Inject Page Hero ────────────────────────────────────── */
	function injectPageHero() {
		// Get page title from MediaWiki's firstHeading
		var titleEl = document.getElementById( 'firstHeading' ) ||
			document.querySelector( '.mw-first-heading' );
		var titleText = titleEl ? titleEl.textContent.trim() : mw.config.get( 'wgTitle' );

		// Build breadcrumb
		var crumb = el( 'div', { className: 'bmc-breadcrumb' }, [
			el( 'a', { href: 'http://biomicro.mit.edu', textContent: 'Home' } ),
			el( 'span', { textContent: '›' } ),
			document.createTextNode( titleText )
		] );

		var heroH1 = el( 'h1', { textContent: titleText } );

		var heroInner = el( 'div', { className: 'bmc-hero-inner' }, [ crumb, heroH1 ] );
		var hero = el( 'div', { className: 'bmc-page-hero' }, [ heroInner ] );

		// Insert hero between header and content
		var mwHead = document.getElementById( 'mw-head' ) ||
			document.querySelector( '.vector-header' );
		var content = document.getElementById( 'content' ) ||
			document.querySelector( '.mw-body' ) ||
			document.querySelector( '.vector-body' );

		if ( mwHead && mwHead.parentNode ) {
			var ref = mwHead.nextSibling;
			mwHead.parentNode.insertBefore( hero, ref );
		} else if ( content && content.parentNode ) {
			content.parentNode.insertBefore( hero, content );
		}
	}

	/* ── 4. Rewrite Footer ──────────────────────────────────────── */
	function rewriteFooter() {
		var footer = document.getElementById( 'footer' ) ||
			document.querySelector( '.mw-footer' );
		if ( !footer ) return;

		var inner = el( 'div', { className: 'bmc-footer-inner' }, [
			// Col 1: address
			el( 'div', {}, [
				el( 'h4', { textContent: 'MIT BioMicro Center' } ),
				( function () {
					var ul = document.createElement( 'ul' );
					[ 'Building 68-322', 'Cambridge, MA 02139' ].forEach( function ( t ) {
						ul.appendChild( el( 'li', { textContent: t } ) );
					} );
					var emailLi = document.createElement( 'li' );
					emailLi.appendChild( el( 'a', {
						href: 'mailto:biomicro@mit.edu',
						textContent: 'biomicro@mit.edu'
					} ) );
					ul.appendChild( emailLi );
					ul.appendChild( el( 'li', { textContent: '617-715-4533' } ) );
					return ul;
				} )()
			] ),
			// Col 2: services
			el( 'div', {}, [
				el( 'h4', { textContent: 'Services' } ),
				( function () {
					var ul = document.createElement( 'ul' );
					[
						{ label: 'Bulk Sequencing', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
						{ label: 'Single Cell', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
						{ label: 'Spatial Genomics', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation' },
						{ label: 'Informatics', href: 'https://igb.mit.edu/' }
					].forEach( function ( item ) {
						var li = document.createElement( 'li' );
						li.appendChild( el( 'a', { href: item.href, textContent: item.label } ) );
						ul.appendChild( li );
					} );
					return ul;
				} )()
			] ),
			// Col 3: resources
			el( 'div', {}, [
				el( 'h4', { textContent: 'Resources' } ),
				( function () {
					var ul = document.createElement( 'ul' );
					[
						{ label: 'FAQs', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ' },
						{ label: 'Forms', href: 'http://biomicro.mit.edu/forms.html' },
						{ label: 'Grant Support & Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' },
						{ label: 'Acknowledgements', href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement' }
					].forEach( function ( item ) {
						var li = document.createElement( 'li' );
						li.appendChild( el( 'a', { href: item.href, textContent: item.label } ) );
						ul.appendChild( li );
					} );
					return ul;
				} )()
			] )
		] );

		var bottom = el( 'div', { className: 'bmc-footer-bottom' }, [
			el( 'span', { textContent: '© ' + new Date().getFullYear() + ' MIT BioMicro Center' } ),
			el( 'span', {}, [
				el( 'a', {
					href: 'https://accessibility.mit.edu',
					target: '_blank',
					textContent: 'Accessibility'
				} )
			] )
		] );

		footer.innerHTML = '';
		footer.appendChild( inner );
		footer.appendChild( bottom );
	}

	/* ── 5. Smooth Scroll ───────────────────────────────────────── */
	function initSmoothScroll() {
		var content = document.querySelector( '.mw-parser-output' );
		if ( !content ) return;
		content.addEventListener( 'click', function ( e ) {
			var a = e.target.closest( 'a[href^="#"]' );
			if ( !a ) return;
			var target = document.getElementById(
				decodeURIComponent( a.getAttribute( 'href' ).slice( 1 ) )
			);
			if ( target ) {
				e.preventDefault();
				target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
				history.pushState( null, '', a.getAttribute( 'href' ) );
			}
		} );
	}

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

	/* ── Entry point ────────────────────────────────────────────── */
	mw.hook( 'wikipage.content' ).add( function () {
		injectTopbar();
		injectHorizontalNav();
		injectPageHero();
		rewriteFooter();
		initSmoothScroll();
		styleUnstyledTables();
	} );

} )();