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
Tag: Manual revert
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* ============================================================
/**
  MIT BioMicro Center — MediaWiki Custom Scripts
* BioMicro Center Wiki Full DOM Replacement
  Skin: Vector-2022
* Paste into: User:USERNAME/common.js
  Scope: User:USERNAME/common.js  (personal preview)
  *
  ============================================================ */
* Strategy:
* 1. Extract wiki article content from MediaWiki's DOM
* 2. Inject the complete about.html shell structure
* 3. Place article content inside the shell
* MediaWiki still runs underneath for editing, search, login, etc.
*/


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


  var WIKI = 'https://bmcwiki.mit.edu';
   /* ── Nav definition (matches about.html exactly) ──────────── */
 
   /* Nav definition — mirrors the mockup structure exactly.
    Update href values if your wiki uses different page titles. */
   var NAV = [
   var NAV = [
     {
     {
       label: 'About',
       label: 'About',
       href: WIKI + '/index.php/BioMicroCenter:About'
       href: 'http://biomicro.mit.edu/about.html',
      match: [ 'BioMicroCenter', 'Main_Page' ]
     },
     },
     {
     {
       label: 'News',
       label: 'News',
       href: WIKI + '/index.php/BioMicroCenter:News',
       href: 'http://biomicro.mit.edu/news.html',
       children: [
      match: [ 'News', 'Seminar' ],
         { label: 'Latest News',       href: WIKI + '/index.php/BioMicroCenter:News' },
       items: [
         { label: 'Seminars',         href: WIKI + '/index.php/BioMicroCenter:Seminars' },
         { label: 'Latest News',       href: 'http://biomicro.mit.edu/news.html' },
         { label: 'Classes & Training',href: 'https://igb.mit.edu/mini-courses', external: true }
         { label: 'Seminars',           href: 'http://biomicro.mit.edu/seminars.html' },
         { label: 'Classes & Training', href: 'https://igb.mit.edu/mini-courses', ext: true }
       ]
       ]
     },
     },
     {
     {
       label: 'Services',
       label: 'Services',
       href: WIKI + '/index.php/BioMicroCenter:Assisted_Services',
       href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services',
       children: [
       match: [ 'Assisted_Services', 'Walkup', 'Service', 'Consumable' ],
         { label: 'Walkup',       href: WIKI + '/index.php/BioMicroCenter:Walk-up_Services' },
      items: [
         { label: 'Assisted',     href: WIKI + '/index.php/BioMicroCenter:Assisted_Services' },
         { label: 'Walkup',     href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation' },
         { label: 'Consumables',   href: WIKI + '/index.php/BioMicroCenter:Consumables' },
         { label: 'Assisted',   href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services' },
         { label: 'Training',     href: 'https://igb.mit.edu/mini-courses', external: true },
         { label: 'Consumables', href: 'http://biomicro.mit.edu/consumables.html' },
         { label: 'Informatics',   href: 'https://igb.mit.edu/', external: true }
         { label: 'Training',   href: 'https://igb.mit.edu/mini-courses', ext: true },
         { label: 'Informatics', href: 'https://igb.mit.edu/', ext: true }
       ]
       ]
     },
     },
     {
     {
       label: 'Submission',
       label: 'Submission',
       href: WIKI + '/index.php/BioMicroCenter:Submission',
       href: 'http://biomicro.mit.edu/submit.html',
       children: [
      match: [ 'Submission', 'Submit', 'Pricing' ],
         { label: 'MIT Users',    group: true },
       items: [
         { label: 'Submit a Sample',   href: WIKI + '/index.php/BioMicroCenter:Submission' },
         { groupLabel: 'MIT Users' },
         { label: 'MIT Pricing',       href: WIKI + '/index.php/MIT:Pricing', external: true },
         { 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 },
         { divider: true },
         { label: 'Non-MIT Users', group: true },
         { groupLabel: 'Non-MIT Users' },
         { label: 'External Submission', href: WIKI + '/index.php/BioMicroCenter:Submission' },
         { label: 'External Submission', href: 'http://biomicro.mit.edu/submit.html' },
         { label: 'External Pricing',    href: WIKI + '/index.php/BioMicroCenter:Grant_Support_%26_Pricing', highlight: true }
         { label: 'External Pricing',    href: 'http://biomicro.mit.edu/pricing_v2.html' }
       ]
       ]
     },
     },
     {
     {
       label: 'Staff',
       label: 'Staff',
       href: WIKI + '/index.php/BioMicroCenter:Staff'
       href: 'http://biomicro.mit.edu/staff.html',
      match: [ 'Staff' ]
     },
     },
     {
     {
       label: 'Resources',
       label: 'Resources',
       href: WIKI + '/index.php/BioMicroCenter:FAQ',
       href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ',
       children: [
       match: [ 'FAQ', 'Resource', 'Form', 'Acknowledgement' ],
         { label: 'FAQs',                   href: WIKI + '/index.php/BioMicroCenter:FAQ' },
      items: [
         { label: 'Forms',                 href: WIKI + '/index.php/BioMicroCenter:Forms' },
         { label: 'FAQs',                   href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ' },
         { label: 'Grant Support & Pricing',href: WIKI + '/index.php/BioMicroCenter:Grant_Support_%26_Pricing' },
         { label: 'Forms',                   href: 'http://biomicro.mit.edu/forms.html' },
         { label: 'Acknowledgements',       href: WIKI + '/index.php/BioMicroCenter:Acknowledgement', external: true }
         { label: 'Grant Support & Pricing', href: 'http://biomicro.mit.edu/pricing_v2.html' },
         { label: 'Acknowledgements',       href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement' }
       ]
       ]
     }
     }
   ];
   ];


 
   /* ── Build topbar HTML ─────────────────────────────────────── */
   /* ── Helpers ─────────────────────────────────────────────── */
   function buildTopbar() {
 
     var d = document.createElement( 'div' );
   function make( tag, cls, html ) {
     d.className = 'bmc-topbar';
     var n = document.createElement( tag );
     d.innerHTML =
     if ( cls ) n.className = cls;
       '<div class="inner">' +
    if ( html ) n.innerHTML = html;
    return n;
  }
 
  /* Detect if a nav item matches the current page */
  function isActive( href ) {
    return window.location.href.indexOf( href ) !== -1;
  }
 
 
  /* ── 1. Build and Inject Topbar ──────────────────────────── */
  function injectTopbar() {
    var bar = make( 'div', 'bmc-topbar' );
     bar.innerHTML =
       '<div class="bmc-inner">' +
         '<a href="mailto:biomicro@mit.edu">biomicro@mit.edu</a>' +
         '<a href="mailto:biomicro@mit.edu">biomicro@mit.edu</a>' +
         '<span class="bmc-sep">|</span>617-715-4533' +
         '<span>|</span>' +
         '<span class="bmc-sep">|</span>Building 68-322' +
        '617-715-4533' +
         '<span>|</span>' +
        'Building 68-322' +
       '</div>';
       '</div>';
     document.body.insertBefore( bar, document.body.firstChild );
     return d;
   }
   }


 
   /* ── Build nav dropdown item ───────────────────────────────── */
   /* ── 2. Build Navigation HTML ────────────────────────────── */
   function buildDropdownMenu( items ) {
   function buildNav() {
     var menu = document.createElement( 'div' );
     var ul = make( 'ul' );
    menu.className = 'bmc-dropdown-menu';
 
     items.forEach( function ( item ) {
     NAV.forEach( function ( item ) {
       if ( item.divider ) {
      var li = make( 'li' );
         var div = document.createElement( 'div' );
      var pageActive = isActive( item.href );
         div.className = 'bmc-divider';
 
         menu.appendChild( div );
       if ( item.children ) {
      } else if ( item.groupLabel ) {
         li.className = 'bmc-dropdown' + ( pageActive ? ' bmc-active' : '' );
        var gl = document.createElement( 'div' );
         li.innerHTML = '<a href="' + item.href + '">' + item.label + '</a>';
        gl.className = 'bmc-group-label';
 
        gl.textContent = item.groupLabel;
        var menu = make( 'div', 'bmc-dropdown-menu' );
        menu.appendChild( gl );
         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.label;
            menu.appendChild( g );
          } else {
            var a = make( 'a' );
            a.href = c.href;
            a.textContent = c.label;
            if ( c.external ) a.target = '_blank';
            if ( c.highlight ) { a.style.fontWeight = '600'; a.style.color = '#a31f34'; }
            menu.appendChild( a );
          }
        } );
        li.appendChild( menu );
       } else {
       } else {
         li.className = pageActive ? 'bmc-active' : '';
         var a = document.createElement( 'a' );
         li.innerHTML = '<a href="' + item.href + '">' + item.label + '</a>';
         a.href = item.href;
        a.textContent = item.label;
        if ( item.ext ) a.target = '_blank';
        menu.appendChild( a );
       }
       }
      ul.appendChild( li );
     } );
     } );
 
     return menu;
     return ul;
   }
   }


 
   /* ── Build full header ─────────────────────────────────────── */
   /* ── 3. Build and Inject Header ──────────────────────────── */
   function buildHeader( currentPage ) {
   function injectHeader() {
    var header = make( 'div', 'bmc-header' );
    var inner  = make( 'div', 'bmc-header-inner' );
 
     /* Logo */
     /* Logo */
     var logo = make( 'a', 'bmc-logo' );
     var logo = document.createElement( 'a' );
     logo.href = WIKI;
    logo.href = 'https://bmcwiki.mit.edu/index.php/BioMicroCenter';
     logo.className = 'bmc-logo';
     logo.innerHTML =
     logo.innerHTML =
       '<div class="bmc-logo-mark">BMC</div>' +
       '<div class="bmc-logo-mark">BMC</div>' +
       '<div class="bmc-logo-text">' +
       '<div class="bmc-logo-text">' +
         '<div class="bmc-logo-name">MIT BioMicro Center</div>' +
         '<span class="bmc-logo-name">MIT BioMicro Center</span>' +
         '<div class="bmc-logo-sub">Integrated Genomics Core Facility</div>' +
         '<span class="bmc-logo-sub">Integrated Genomics Core Facility</span>' +
       '</div>';
       '</div>';


     /* Nav */
     /* Nav */
     var nav = make( 'nav', 'bmc-nav' );
     var ul = document.createElement( 'ul' );
    nav.appendChild( buildNav() );
    NAV.forEach( function ( item ) {
      var li = document.createElement( 'li' );
      var isActive = ( item.match || [] ).some( function ( m ) {
        return currentPage.indexOf( m ) !== -1;
      } );
      if ( isActive ) li.classList.add( 'bmc-active' );
      if ( item.items ) li.classList.add( 'bmc-dropdown' );
 
      var a = document.createElement( 'a' );
      a.href = item.href;
      a.textContent = item.label;
      li.appendChild( a );
 
      if ( item.items ) {
        li.appendChild( buildDropdownMenu( item.items ) );
      }
      ul.appendChild( li );
    } );


    /* Right side: move Vector's search + user links here */
     var nav = document.createElement( 'nav' );
     var right = make( 'div', 'bmc-header-right' );
    nav.className = 'bmc-nav';
    nav.appendChild( ul );


     var vectorSearch = document.querySelector( '.vector-search-box, #p-search' );
    /* Search */
     if ( vectorSearch ) {
     var searchForm = document.createElement( 'form' );
      vectorSearch.style.cssText = 'margin:0;padding:0;';
    searchForm.className = 'bmc-search-form';
       right.appendChild( vectorSearch );
     searchForm.method = 'get';
    }
    searchForm.action = '/index.php';
    searchForm.innerHTML =
      '<input type="hidden" name="title" value="Special:Search">' +
      '<input type="search" name="search" placeholder="Search wiki…" aria-label="Search">' +
       '<button type="submit">&#9906;</button>';


     var vectorUser = document.querySelector( '.vector-user-links, #p-personal' );
     var right = document.createElement( 'div' );
     if ( vectorUser ) {
     right.className = 'bmc-header-right';
      vectorUser.style.cssText = 'margin:0;padding:0;';
    right.appendChild( nav );
      right.appendChild( vectorUser );
     right.appendChild( searchForm );
     }


    /* Inner wrapper */
    var inner = document.createElement( 'div' );
    inner.className = 'bmc-header-inner';
     inner.appendChild( logo );
     inner.appendChild( logo );
    inner.appendChild( nav );
     inner.appendChild( right );
     inner.appendChild( right );
    var header = document.createElement( 'header' );
    header.className = 'bmc-header';
     header.appendChild( inner );
     header.appendChild( inner );
    return header;
  }
  /* ── Build page hero ───────────────────────────────────────── */
  function buildHero( titleText ) {
    var crumb = document.createElement( 'div' );
    crumb.className = 'bmc-breadcrumb';
    crumb.innerHTML =
      '<a href="http://biomicro.mit.edu">Home</a>' +
      '<span class="sep">›</span>' +
      document.createTextNode( titleText ).textContent; // plain text, no XSS
    var h1 = document.createElement( 'h1' );
    h1.textContent = titleText;
    var inner = document.createElement( 'div' );
    inner.className = 'inner';
    inner.appendChild( crumb );
    inner.appendChild( h1 );


    /* Insert after topbar */
     var hero = document.createElement( 'div' );
     var topbar = document.querySelector( '.bmc-topbar' );
     hero.className = 'bmc-page-hero';
     if ( topbar && topbar.nextSibling ) {
     hero.appendChild( inner );
      document.body.insertBefore( header, topbar.nextSibling );
     return hero;
     } else {
      document.body.insertBefore( header, document.body.firstChild );
     }
   }
   }


  /* ── Build sidebar TOC from MediaWiki #toc ─────────────────── */
  function buildSidebarToc( mwToc ) {
    var toc = document.createElement( 'div' );
    toc.className = 'bmc-toc';
    var h3 = document.createElement( 'h3' );
    h3.textContent = 'On this page';
    toc.appendChild( h3 );


  /* ── 4. Build and Inject Hero Banner ─────────────────────── */
    if ( mwToc ) {
  function injectHero() {
      /* Clone only the list from the MediaWiki TOC */
    /* Don't show hero on Special pages or edit forms */
      var mwList = mwToc.querySelector( 'ul' );
    var ns = mw.config.get( 'wgNamespaceNumber' );
      if ( mwList ) {
    if ( ns < 0 ) return; /* Special: pages */
        var cloned = mwList.cloneNode( true );
    if ( document.querySelector( '#editform, .mw-editform' ) ) return;
        /* Mark sub-items */
        cloned.querySelectorAll( 'li li' ).forEach( function ( li ) {
          li.classList.add( 'bmc-sub' );
        } );
        toc.appendChild( cloned );
      }
    } else {
      /* No TOC generated — leave the sidebar empty or show nothing */
      return null;
    }


    /* Get the page title from the hidden h1 */
     var aside = document.createElement( 'aside' );
     var h1 = document.querySelector( 'h1.firstHeading, .mw-first-heading' );
    aside.className = 'bmc-sidebar';
     var title = h1 ? h1.textContent.trim() : mw.config.get( 'wgTitle' );
     aside.appendChild( toc );
    return aside;
  }


    /* Build breadcrumb: Home > Title */
  /* ── Build footer ──────────────────────────────────────────── */
     var hero = make( 'div', 'bmc-hero' );
  function buildFooter() {
     hero.innerHTML =
     var inner = document.createElement( 'div' );
       '<div class="bmc-inner">' +
    inner.className = 'bmc-footer-inner';
         '<div class="bmc-breadcrumb">' +
     inner.innerHTML =
           '<a href="' + WIKI + '">Home</a>' +
       '<div>' +
           '<span class="bmc-sep"></span>' +
        '<h4>MIT BioMicro Center</h4>' +
           mw.html.escape( title ) +
        '<ul>' +
         '</div>' +
          '<li>Building 68-322</li>' +
         '<h1>' + mw.html.escape( title ) + '</h1>' +
          '<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="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services">Bulk Sequencing</a></li>' +
           '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services">Single Cell</a></li>' +
           '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation">Spatial Genomics</a></li>' +
           '<li><a href="https://igb.mit.edu/" target="_blank">Informatics</a></li>' +
         '</ul>' +
      '</div>' +
      '<div>' +
         '<h4>Resources</h4>' +
        '<ul>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ">FAQs</a></li>' +
          '<li><a href="http://biomicro.mit.edu/forms.html">Forms</a></li>' +
          '<li><a href="http://biomicro.mit.edu/pricing_v2.html">Grant Support &amp; Pricing</a></li>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement">Acknowledgements</a></li>' +
        '</ul>' +
       '</div>';
       '</div>';


     /* Insert before the main page container */
     var bottom = document.createElement( 'div' );
     var container = document.querySelector( '.mw-page-container' );
    bottom.className = 'bmc-footer-bottom';
     if ( container ) {
    bottom.innerHTML =
      container.parentNode.insertBefore( hero, container );
      '<span>&copy; ' + new Date().getFullYear() + ' MIT BioMicro Center</span>' +
     }
      '<span>' +
        '<a href="https://bmcwiki.mit.edu/index.php/Special:UserLogin">Log in</a>' +
        ' &nbsp;|&nbsp; ' +
        '<a href="https://accessibility.mit.edu" target="_blank">Accessibility</a>' +
      '</span>';
 
     var footer = document.createElement( 'footer' );
    footer.className = 'bmc-footer';
     footer.appendChild( inner );
    footer.appendChild( bottom );
     return footer;
   }
   }


  /* ── Smooth scroll for anchor links ───────────────────────── */
  function initSmoothScroll( container ) {
    container.addEventListener( 'click', function ( e ) {
      var a = e.target.closest( 'a[href^="#"]' );
      if ( !a ) return;
      var id = decodeURIComponent( a.getAttribute( 'href' ).slice( 1 ) );
      var target = document.getElementById( id );
      if ( target ) {
        e.preventDefault();
        target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
        history.pushState( null, '', '#' + id );
      }
    } );
  }


   /* ── 5. Wrap Content in Our Layout Grid ──────────────────── */
   /* ── Main: build and inject the shell ─────────────────────── */
   function wrapLayout() {
   function buildShell() {
     /* Vector-2022 puts TOC and content inside .mw-content-container.
     var currentPage = mw.config.get( 'wgPageName' ) || '';
      We pull them into our bmc-page-layout grid. */
    var contentContainer = document.querySelector( '.mw-content-container' );
    if ( !contentContainer ) return;


     var layout = make( 'div', 'bmc-page-layout' );
    /* 1. Extract wiki content BEFORE any DOM manipulation */
     var mwContentText = document.getElementById( 'mw-content-text' );
    if ( !mwContentText ) return; /* not a content page, bail */


    /* Left: sidebar — use Vector's TOC panel if it exists */
     var contentClone = mwContentText.cloneNode( true );
     var sidebar = make( 'div', 'bmc-sidebar' );
    var toc = document.querySelector( '#mw-panel-toc, .vector-toc-landmark' );
    if ( toc ) {
      sidebar.appendChild( toc );
    }
    layout.appendChild( sidebar );


     /* Right: content column — move Vector's #mw-content into it */
     /* 2. Extract page title */
     var contentCol = make( 'div', 'bmc-content-col' );
     var titleEl = document.getElementById( 'firstHeading' ) ||
    var mwContent = document.querySelector( '#mw-content' );
      document.querySelector( '.mw-first-heading' );
     if ( mwContent ) {
     var titleText = titleEl
       contentCol.appendChild( mwContent );
       ? titleEl.textContent.trim()
    }
      : ( mw.config.get( 'wgTitle' ) || 'BioMicro Center' );
    layout.appendChild( contentCol );


     /* Replace the content container's children with our layout */
     /* 3. Extract MediaWiki TOC from the cloned content */
     contentContainer.innerHTML = '';
     var mwToc = contentClone.querySelector( '#toc, .toc' );
     contentContainer.appendChild( layout );
     if ( mwToc ) mwToc.parentNode.removeChild( mwToc ); /* remove from content body */
  }


    /* 4. Build shell elements */
    var topbar = buildTopbar();
    var header = buildHeader( currentPage );
    var hero  = buildHero( titleText );


  /* ── 6. Build and Inject Footer ──────────────────────────── */
    /* Page layout grid */
  function injectFooter() {
     var layout = document.createElement( 'div' );
     var footer = make( 'div', 'bmc-footer' );
     layout.className = 'bmc-page-layout';
     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 );
     /* Sidebar */
  }
    var sidebar = buildSidebarToc( mwToc );
    if ( sidebar ) {
      layout.appendChild( sidebar );
    } else {
      /* No TOC — collapse to single-column via inline style */
      layout.style.gridTemplateColumns = '1fr';
    }


    /* Main content area */
    var main = document.createElement( 'main' );
    main.className = 'bmc-content';
    main.appendChild( contentClone );
    layout.appendChild( main );


  /* ── 7. Scroll Offset Fix (anchor links) ─────────────────── */
     var footer = buildFooter();
  function fixScrollOffset() {
    var OFFSET = 88;
     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 );
    } );
  }


    /* 5. Build wrapper */
    var wrapper = document.createElement( 'div' );
    wrapper.id = 'bmc-wrapper';
    wrapper.appendChild( topbar );
    wrapper.appendChild( header );
    wrapper.appendChild( hero );
    wrapper.appendChild( layout );
    wrapper.appendChild( footer );


  /* ── 8. Tab Panel System ─────────────────────────────────── */
    /* 6. Inject into body (prepend so it appears first) */
  function initTabs() {
     document.body.insertBefore( wrapper, document.body.firstChild );
     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' );
     /* 7. Smooth scroll */
     if ( !document.querySelector( '.tab-panel.active' ) && panels[ 0 ] ) panels[ 0 ].classList.add( 'active' );
    initSmoothScroll( main );
     initSmoothScroll( sidebar || main );


     btns.forEach( function ( btn ) {
     /* 8. Auto-style plain tables in content */
       btn.addEventListener( 'click', function () {
    main.querySelectorAll(
        btns.forEach( function ( t ) { t.classList.remove( 'active' ); } );
       '.mw-parser-output table:not(.wikitable):not(.infobox):not(.navbox)'
        panels.forEach( function ( p ) { p.classList.remove( 'active' ); } );
    ).forEach( function ( t ) {
        btn.classList.add( 'active' );
      t.classList.add( 'wikitable' );
        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 - 68, behavior: 'smooth' } );
      } );
     } );
     } );
   }
   }


  /* ── Entry point ───────────────────────────────────────────── */
  mw.hook( 'wikipage.content' ).add( function () {
    /* Skip special pages (edit forms, history, etc.) to not break them */
    var ns = mw.config.get( 'wgNamespaceNumber' );
    var action = mw.config.get( 'wgAction' );
    if ( action !== 'view' ) return;
    if ( ns < 0 ) return; /* Special: pages */


  /* ── Run Everything ──────────────────────────────────────── */
    buildShell();
  injectTopbar();
   } );
  injectHeader();
   injectHero();
  wrapLayout();
  injectFooter();
  fixScrollOffset();
  initTabs();


} );
} )();

Latest revision as of 23:19, 8 May 2026

/**
 * BioMicro Center Wiki — Full DOM Replacement
 * Paste into: User:USERNAME/common.js
 *
 * Strategy:
 * 1. Extract wiki article content from MediaWiki's DOM
 * 2. Inject the complete about.html shell structure
 * 3. Place article content inside the shell
 * MediaWiki still runs underneath for editing, search, login, etc.
 */

( function () {
  'use strict';

  /* ── Nav definition (matches about.html exactly) ──────────── */
  var NAV = [
    {
      label: 'About',
      href: 'http://biomicro.mit.edu/about.html',
      match: [ 'BioMicroCenter', 'Main_Page' ]
    },
    {
      label: 'News',
      href: 'http://biomicro.mit.edu/news.html',
      match: [ 'News', 'Seminar' ],
      items: [
        { 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', ext: true }
      ]
    },
    {
      label: 'Services',
      href: 'https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services',
      match: [ 'Assisted_Services', 'Walkup', 'Service', 'Consumable' ],
      items: [
        { 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', ext: true },
        { label: 'Informatics', href: 'https://igb.mit.edu/', ext: true }
      ]
    },
    {
      label: 'Submission',
      href: 'http://biomicro.mit.edu/submit.html',
      match: [ 'Submission', 'Submit', 'Pricing' ],
      items: [
        { 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', 'Resource', 'Form', 'Acknowledgement' ],
      items: [
        { 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' }
      ]
    }
  ];

  /* ── Build topbar HTML ─────────────────────────────────────── */
  function buildTopbar() {
    var d = document.createElement( 'div' );
    d.className = 'bmc-topbar';
    d.innerHTML =
      '<div class="inner">' +
        '<a href="mailto:biomicro@mit.edu">biomicro@mit.edu</a>' +
        '<span>|</span>' +
        '617-715-4533' +
        '<span>|</span>' +
        'Building 68-322' +
      '</div>';
    return d;
  }

  /* ── Build nav dropdown item ───────────────────────────────── */
  function buildDropdownMenu( items ) {
    var menu = document.createElement( 'div' );
    menu.className = 'bmc-dropdown-menu';
    items.forEach( function ( item ) {
      if ( item.divider ) {
        var div = document.createElement( 'div' );
        div.className = 'bmc-divider';
        menu.appendChild( div );
      } else if ( item.groupLabel ) {
        var gl = document.createElement( 'div' );
        gl.className = 'bmc-group-label';
        gl.textContent = item.groupLabel;
        menu.appendChild( gl );
      } else {
        var a = document.createElement( 'a' );
        a.href = item.href;
        a.textContent = item.label;
        if ( item.ext ) a.target = '_blank';
        menu.appendChild( a );
      }
    } );
    return menu;
  }

  /* ── Build full header ─────────────────────────────────────── */
  function buildHeader( currentPage ) {
    /* Logo */
    var logo = document.createElement( 'a' );
    logo.href = 'https://bmcwiki.mit.edu/index.php/BioMicroCenter';
    logo.className = 'bmc-logo';
    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 ul = document.createElement( 'ul' );
    NAV.forEach( function ( item ) {
      var li = document.createElement( 'li' );
      var isActive = ( item.match || [] ).some( function ( m ) {
        return currentPage.indexOf( m ) !== -1;
      } );
      if ( isActive ) li.classList.add( 'bmc-active' );
      if ( item.items ) li.classList.add( 'bmc-dropdown' );

      var a = document.createElement( 'a' );
      a.href = item.href;
      a.textContent = item.label;
      li.appendChild( a );

      if ( item.items ) {
        li.appendChild( buildDropdownMenu( item.items ) );
      }
      ul.appendChild( li );
    } );

    var nav = document.createElement( 'nav' );
    nav.className = 'bmc-nav';
    nav.appendChild( ul );

    /* Search */
    var searchForm = document.createElement( 'form' );
    searchForm.className = 'bmc-search-form';
    searchForm.method = 'get';
    searchForm.action = '/index.php';
    searchForm.innerHTML =
      '<input type="hidden" name="title" value="Special:Search">' +
      '<input type="search" name="search" placeholder="Search wiki…" aria-label="Search">' +
      '<button type="submit">&#9906;</button>';

    var right = document.createElement( 'div' );
    right.className = 'bmc-header-right';
    right.appendChild( nav );
    right.appendChild( searchForm );

    /* Inner wrapper */
    var inner = document.createElement( 'div' );
    inner.className = 'bmc-header-inner';
    inner.appendChild( logo );
    inner.appendChild( right );

    var header = document.createElement( 'header' );
    header.className = 'bmc-header';
    header.appendChild( inner );
    return header;
  }

  /* ── Build page hero ───────────────────────────────────────── */
  function buildHero( titleText ) {
    var crumb = document.createElement( 'div' );
    crumb.className = 'bmc-breadcrumb';
    crumb.innerHTML =
      '<a href="http://biomicro.mit.edu">Home</a>' +
      '<span class="sep">›</span>' +
      document.createTextNode( titleText ).textContent; // plain text, no XSS

    var h1 = document.createElement( 'h1' );
    h1.textContent = titleText;

    var inner = document.createElement( 'div' );
    inner.className = 'inner';
    inner.appendChild( crumb );
    inner.appendChild( h1 );

    var hero = document.createElement( 'div' );
    hero.className = 'bmc-page-hero';
    hero.appendChild( inner );
    return hero;
  }

  /* ── Build sidebar TOC from MediaWiki #toc ─────────────────── */
  function buildSidebarToc( mwToc ) {
    var toc = document.createElement( 'div' );
    toc.className = 'bmc-toc';

    var h3 = document.createElement( 'h3' );
    h3.textContent = 'On this page';
    toc.appendChild( h3 );

    if ( mwToc ) {
      /* Clone only the list from the MediaWiki TOC */
      var mwList = mwToc.querySelector( 'ul' );
      if ( mwList ) {
        var cloned = mwList.cloneNode( true );
        /* Mark sub-items */
        cloned.querySelectorAll( 'li li' ).forEach( function ( li ) {
          li.classList.add( 'bmc-sub' );
        } );
        toc.appendChild( cloned );
      }
    } else {
      /* No TOC generated — leave the sidebar empty or show nothing */
      return null;
    }

    var aside = document.createElement( 'aside' );
    aside.className = 'bmc-sidebar';
    aside.appendChild( toc );
    return aside;
  }

  /* ── Build footer ──────────────────────────────────────────── */
  function buildFooter() {
    var inner = document.createElement( 'div' );
    inner.className = 'bmc-footer-inner';
    inner.innerHTML =
      '<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="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services">Bulk Sequencing</a></li>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Assisted_Services">Single Cell</a></li>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Walkup_Instrumentation">Spatial Genomics</a></li>' +
          '<li><a href="https://igb.mit.edu/" target="_blank">Informatics</a></li>' +
        '</ul>' +
      '</div>' +
      '<div>' +
        '<h4>Resources</h4>' +
        '<ul>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:FAQ">FAQs</a></li>' +
          '<li><a href="http://biomicro.mit.edu/forms.html">Forms</a></li>' +
          '<li><a href="http://biomicro.mit.edu/pricing_v2.html">Grant Support &amp; Pricing</a></li>' +
          '<li><a href="https://bmcwiki.mit.edu/index.php/BioMicroCenter:Acknowledgement">Acknowledgements</a></li>' +
        '</ul>' +
      '</div>';

    var bottom = document.createElement( 'div' );
    bottom.className = 'bmc-footer-bottom';
    bottom.innerHTML =
      '<span>&copy; ' + new Date().getFullYear() + ' MIT BioMicro Center</span>' +
      '<span>' +
        '<a href="https://bmcwiki.mit.edu/index.php/Special:UserLogin">Log in</a>' +
        ' &nbsp;|&nbsp; ' +
        '<a href="https://accessibility.mit.edu" target="_blank">Accessibility</a>' +
      '</span>';

    var footer = document.createElement( 'footer' );
    footer.className = 'bmc-footer';
    footer.appendChild( inner );
    footer.appendChild( bottom );
    return footer;
  }

  /* ── Smooth scroll for anchor links ───────────────────────── */
  function initSmoothScroll( container ) {
    container.addEventListener( 'click', function ( e ) {
      var a = e.target.closest( 'a[href^="#"]' );
      if ( !a ) return;
      var id = decodeURIComponent( a.getAttribute( 'href' ).slice( 1 ) );
      var target = document.getElementById( id );
      if ( target ) {
        e.preventDefault();
        target.scrollIntoView( { behavior: 'smooth', block: 'start' } );
        history.pushState( null, '', '#' + id );
      }
    } );
  }

  /* ── Main: build and inject the shell ─────────────────────── */
  function buildShell() {
    var currentPage = mw.config.get( 'wgPageName' ) || '';

    /* 1. Extract wiki content BEFORE any DOM manipulation */
    var mwContentText = document.getElementById( 'mw-content-text' );
    if ( !mwContentText ) return; /* not a content page, bail */

    var contentClone = mwContentText.cloneNode( true );

    /* 2. Extract page title */
    var titleEl = document.getElementById( 'firstHeading' ) ||
      document.querySelector( '.mw-first-heading' );
    var titleText = titleEl
      ? titleEl.textContent.trim()
      : ( mw.config.get( 'wgTitle' ) || 'BioMicro Center' );

    /* 3. Extract MediaWiki TOC from the cloned content */
    var mwToc = contentClone.querySelector( '#toc, .toc' );
    if ( mwToc ) mwToc.parentNode.removeChild( mwToc ); /* remove from content body */

    /* 4. Build shell elements */
    var topbar = buildTopbar();
    var header = buildHeader( currentPage );
    var hero   = buildHero( titleText );

    /* Page layout grid */
    var layout = document.createElement( 'div' );
    layout.className = 'bmc-page-layout';

    /* Sidebar */
    var sidebar = buildSidebarToc( mwToc );
    if ( sidebar ) {
      layout.appendChild( sidebar );
    } else {
      /* No TOC — collapse to single-column via inline style */
      layout.style.gridTemplateColumns = '1fr';
    }

    /* Main content area */
    var main = document.createElement( 'main' );
    main.className = 'bmc-content';
    main.appendChild( contentClone );
    layout.appendChild( main );

    var footer = buildFooter();

    /* 5. Build wrapper */
    var wrapper = document.createElement( 'div' );
    wrapper.id = 'bmc-wrapper';
    wrapper.appendChild( topbar );
    wrapper.appendChild( header );
    wrapper.appendChild( hero );
    wrapper.appendChild( layout );
    wrapper.appendChild( footer );

    /* 6. Inject into body (prepend so it appears first) */
    document.body.insertBefore( wrapper, document.body.firstChild );

    /* 7. Smooth scroll */
    initSmoothScroll( main );
    initSmoothScroll( sidebar || main );

    /* 8. Auto-style plain tables in content */
    main.querySelectorAll(
      '.mw-parser-output table:not(.wikitable):not(.infobox):not(.navbox)'
    ).forEach( function ( t ) {
      t.classList.add( 'wikitable' );
    } );
  }

  /* ── Entry point ───────────────────────────────────────────── */
  mw.hook( 'wikipage.content' ).add( function () {
    /* Skip special pages (edit forms, history, etc.) to not break them */
    var ns = mw.config.get( 'wgNamespaceNumber' );
    var action = mw.config.get( 'wgAction' );
    if ( action !== 'view' ) return;
    if ( ns < 0 ) return; /* Special: pages */

    buildShell();
  } );

} )();