Jump to content

MediaWiki:Gadget-wix-nav.js: Difference between revisions

From Insurer Brain
Content deleted Content added
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 154: Line 154:
}
}


// 2. Detect current page
// 2. Detect current page and its index
var currentPage = mw.config.get( 'wgPageName' ).replace( / /g, '_' );
var currentPage = mw.config.get( 'wgPageName' ).replace( / /g, '_' );
var currentLabel = 'Navigate to\u2026';
var currentLabel = 'Navigate to\u2026';
var currentIdx = -1;


pages.forEach( function ( entry ) {
pages.forEach( function ( entry, i ) {
var normalizedPage = entry[ 1 ].replace( / /g, '_' );
var normalizedPage = entry[ 1 ].replace( / /g, '_' );
if ( normalizedPage === currentPage ) {
if ( normalizedPage === currentPage ) {
currentLabel = entry[ 0 ];
currentLabel = entry[ 0 ];
currentIdx = i;
}
}
} );
} );
Line 168: Line 170:
wix.empty( container );
wix.empty( container );


var wrapper = wix.el( 'div', {
var dropdown = wix.el( 'div', {
className: 'wix-dropdown',
className: 'wix-dropdown',
'role': 'navigation',
'role': 'navigation',
Line 213: Line 215:
} );
} );


wrapper.appendChild( toggle );
dropdown.appendChild( toggle );
wrapper.appendChild( panel );
dropdown.appendChild( panel );

container.appendChild( wrapper );
// 4. Back / Next buttons
var isFirst = currentIdx <= 0;
var isLast = currentIdx >= pages.length - 1;

var btnBack = wix.el( 'a', {
className: 'wix-dropdown-nav-btn'
}, [ wix.el( 'span', { className: 'wix-dropdown-nav-arrow', textContent: '\u25BC' } ) ] );

var btnNext = wix.el( 'a', {
className: 'wix-dropdown-nav-btn'
}, [ wix.el( 'span', { className: 'wix-dropdown-nav-arrow wix-dropdown-nav-arrow--next', textContent: '\u25BC' } ) ] );

if ( isFirst || currentIdx === -1 ) {
btnBack.classList.add( 'wix-dropdown-nav-btn--disabled' );
btnBack.removeAttribute( 'href' );
} else {
btnBack.setAttribute( 'href', mw.util.getUrl( pages[ currentIdx - 1 ][ 1 ] ) );
}

if ( isLast || currentIdx === -1 ) {
btnNext.classList.add( 'wix-dropdown-nav-btn--disabled' );
btnNext.removeAttribute( 'href' );
} else {
btnNext.setAttribute( 'href', mw.util.getUrl( pages[ currentIdx + 1 ][ 1 ] ) );
}

// 5. Assemble: Back | Dropdown | Next
var row = wix.el( 'div', { className: 'wix-dropdown-row' }, [
btnBack,
dropdown,
btnNext
] );

container.appendChild( row );

// 6. Make nav buttons square (width = height, measured after layout)
setTimeout( function () {
var h = toggle.offsetHeight;
if ( h ) {
btnBack.style.width = h + 'px';
btnNext.style.width = h + 'px';
}
}, 0 );


// 4. Toggle open/close
// 7. Toggle open/close
var isOpen = false;
var isOpen = false;


Line 226: Line 271:
} );
} );


// 5. Close on click outside
// 7. Close on click outside
document.addEventListener( 'click', function ( e ) {
document.addEventListener( 'click', function ( e ) {
if ( isOpen && !wrapper.contains( e.target ) ) {
if ( isOpen && !dropdown.contains( e.target ) ) {
isOpen = false;
isOpen = false;
toggle.classList.remove( 'wix-dropdown-toggle--open' );
toggle.classList.remove( 'wix-dropdown-toggle--open' );

Latest revision as of 20:29, 6 April 2026

/* ================================================================
   WIX-NAV.JS — Wiki Interactive Experience: Training Navigation
   ================================================================
   Depends on: ext.gadget.wix-core  (window.wix must exist)

   Finds every container with data-wix-module="nav", reads the
   page list from data-wix-pages (JSON), and builds a horizontal
   navigation bar with the current page highlighted.

   DOM contract (set by wikitext snippet):
   ─────────────────────────────────────────
   Container:   [data-wix-module="nav"]
                  data-wix-pages   JSON array of [label, pageName] pairs

   Example:
     data-wix-pages='[["Module 1","Internal:Training/IFRS17/module-1"],
                      ["Module 2","Internal:Training/IFRS17/module-2"]]'
   ================================================================ */

( function () {
  'use strict';

  /* ── SVG Icon Registry ───────────────────────────────────────
     28×28 viewBox, stroke-based icons for nav cards.
     Add new entries as new subjects appear on the wiki.
     ──────────────────────────────────────────────────────────── */

  var NAV_ICONS = {
    shield:    '<path d="M14 3L4 7v6c0 5.5 4.3 10.6 10 12 5.7-1.4 10-6.5 10-12V7L14 3z"/><path d="M10 14l3 3 5-6"/>',
    document:  '<rect x="6" y="3" width="16" height="22" rx="2"/><path d="M10 8h8M10 12h8M10 16h5"/>',
    pen:       '<path d="M5 23l1.5-5L19 5.5a2 2 0 012.8 2.8L9.5 20.8z"/><path d="M15 9l3 3"/>',
    clipboard: '<path d="M9 3h10a2 2 0 012 2v18a2 2 0 01-2 2H9a2 2 0 01-2-2V5a2 2 0 012-2z"/><path d="M11 3v2h6V3"/><path d="M11 10h6M11 14h6M11 18h4"/>',
    layers:    '<path d="M14 3L3 9l11 6 11-6L14 3z"/><path d="M3 14l11 6 11-6"/><path d="M3 19l11 6 11-6"/>',
    warning:   '<path d="M14 4L3 23h22L14 4z"/><path d="M14 10v6"/><circle cx="14" cy="19" r="1" fill="currentColor" stroke="none"/>',
    chart:     '<path d="M4 24V4"/><path d="M4 20h20"/><path d="M7 16l5-5 4 3 6-7"/>',
    building:  '<path d="M5 24V8l9-5 9 5v16"/><path d="M5 24h18"/><path d="M11 24v-6h6v6"/><path d="M10 10h2M16 10h2M10 14h2M16 14h2"/>',
    tag:       '<path d="M4 4h10l10 10-10 10L4 14V4z"/><circle cx="9" cy="9" r="1.5" fill="currentColor" stroke="none"/>',
    coins:     '<ellipse cx="14" cy="20" rx="8" ry="3"/><path d="M6 20v-4c0-1.7 3.6-3 8-3s8 1.3 8 3v4"/><path d="M6 16v-4c0-1.7 3.6-3 8-3s8 1.3 8 3v4"/>',
    globe:     '<circle cx="14" cy="14" r="10"/><ellipse cx="14" cy="14" rx="4.5" ry="10"/><path d="M4.5 10h19M4.5 18h19"/>',
    heart:     '<path d="M14 24s-8-5.5-8-11a5 5 0 0110 0 5 5 0 0110 0c0 5.5-8 11-8 11z"/>',
    car:       '<path d="M4 18h20M6.5 11l2-4.5h11L21.5 11M5 18v2.5a1 1 0 001 1h2a1 1 0 001-1V18M19 18v2.5a1 1 0 001 1h2a1 1 0 001-1V18"/><rect x="4" y="11" width="20" height="7" rx="2"/>',
    home:      '<path d="M4 13l10-8 10 8"/><path d="M6 12v10a1 1 0 001 1h14a1 1 0 001-1V12"/><path d="M11 23v-6h6v6"/>',
    briefcase: '<rect x="3" y="10" width="22" height="13" rx="2"/><path d="M10 10V7a2 2 0 012-2h4a2 2 0 012 2v3"/><path d="M3 16h22"/>',
    health:    '<rect x="4" y="4" width="20" height="20" rx="4"/><path d="M14 9v10M9 14h10"/>',
    scale:     '<path d="M14 3v20"/><path d="M5 8l9-3 9 3"/><path d="M2 16a5 5 0 005 0 5 5 0 005 0"/><path d="M16 16a5 5 0 005 0 5 5 0 005 0"/><path d="M5 8v8M23 8v8"/>',
    book:      '<path d="M4 4a2 2 0 012-2h5a1 1 0 011 1v22a1 1 0 01-1-1C11 22 8 22 6 22a2 2 0 01-2-2V4z"/><path d="M24 4a2 2 0 00-2-2h-5a1 1 0 00-1 1v22a1 1 0 001-1c0-2 3-2 5-2a2 2 0 002-2V4z"/>',
    umbrella:  '<path d="M14 3a10 10 0 0110 10H14V23a2 2 0 01-4 0"/><path d="M4 13a10 10 0 0110-10"/>',
    people:    '<circle cx="10" cy="8" r="3"/><path d="M4 20v-2a4 4 0 018 0v2"/><circle cx="19" cy="8" r="3"/><path d="M16 20v-2a4 4 0 018 0v2"/>',
    lock:      '<rect x="7" y="13" width="14" height="11" rx="2"/><path d="M10 13V9a4 4 0 018 0v4"/><circle cx="14" cy="19" r="1.5" fill="currentColor" stroke="none"/>',
    gear:      '<circle cx="14" cy="14" r="4"/><path d="M14 2v3M14 23v3M2 14h3M23 14h3M5.1 5.1l2.1 2.1M20.8 20.8l2.1 2.1M5.1 22.9l2.1-2.1M20.8 7.2l2.1-2.1"/>'
  };

  var ARROW_SVG = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7h8M8 4l3 3-3 3"/></svg>';

  var FALLBACK_ICON = '<circle cx="14" cy="14" r="8"/>';


  /* ── Guard ──────────────────────────────────────────────────── */

  mw.hook( 'wikipage.content' ).add( function () {
    var navContainers = wix.initModules( 'nav' );
    navContainers.forEach( initNav );

    var dropdownContainers = wix.initModules( 'nav-dropdown' );
    dropdownContainers.forEach( initNavDropdown );

    var cardContainers = wix.initModules( 'nav-cards' );
    cardContainers.forEach( initNavCards );
  } );


  /* ── Main init ──────────────────────────────────────────────── */

  function initNav( container ) {
    // 1. Read and parse page list
    var raw = wix.data( container, 'wix-pages', '[]' );
    var pages;
    try {
      pages = JSON.parse( raw );
    } catch ( e ) {
      return;
    }
    if ( !pages.length ) {
      return;
    }

    // 2. Detect current page
    var currentPage = mw.config.get( 'wgPageName' ).replace( / /g, '_' );

    // 3. Build menu
    wix.empty( container );

    var menu = wix.el( 'div', {
      className: 'wix-menu',
      'role': 'navigation',
      'aria-label': 'Training navigation'
    } );

    var currentBtn = null;

    pages.forEach( function ( entry ) {
      var label = entry[ 0 ];
      var pageName = entry[ 1 ];
      var normalizedPage = pageName.replace( / /g, '_' );
      var isCurrent = ( normalizedPage === currentPage );
      var btn;

      if ( isCurrent ) {
        btn = wix.el( 'span', {
          className: 'wix-menu-btn wix-menu-btn--current',
          textContent: label,
          'aria-current': 'page'
        } );
        currentBtn = btn;
      } else {
        btn = wix.el( 'a', {
          className: 'wix-menu-btn',
          textContent: label,
          href: mw.util.getUrl( pageName )
        } );
      }

      menu.appendChild( btn );
    } );

    container.appendChild( menu );

    // 4. Scroll current button into view on mobile
    if ( currentBtn ) {
      setTimeout( function () {
        currentBtn.scrollIntoView( {
          inline: 'center',
          block: 'nearest',
          behavior: 'smooth'
        } );
      }, 0 );
    }
  }


  /* ── Dropdown init ──────────────────────────────────────────── */

  function initNavDropdown( container ) {
    // 1. Read and parse page list
    var raw = wix.data( container, 'wix-pages', '[]' );
    var pages;
    try {
      pages = JSON.parse( raw );
    } catch ( e ) {
      return;
    }
    if ( !pages.length ) {
      return;
    }

    // 2. Detect current page and its index
    var currentPage = mw.config.get( 'wgPageName' ).replace( / /g, '_' );
    var currentLabel = 'Navigate to\u2026';
    var currentIdx = -1;

    pages.forEach( function ( entry, i ) {
      var normalizedPage = entry[ 1 ].replace( / /g, '_' );
      if ( normalizedPage === currentPage ) {
        currentLabel = entry[ 0 ];
        currentIdx = i;
      }
    } );

    // 3. Build dropdown
    wix.empty( container );

    var dropdown = wix.el( 'div', {
      className: 'wix-dropdown',
      'role': 'navigation',
      'aria-label': 'Training navigation'
    } );

    // Toggle button
    var chevron = wix.el( 'span', {
      className: 'wix-dropdown-chevron',
      textContent: '\u25BC'
    } );
    var toggle = wix.el( 'button', {
      className: 'wix-dropdown-toggle'
    }, [
      wix.el( 'span', { textContent: currentLabel } ),
      chevron
    ] );

    // Panel
    var panel = wix.el( 'div', { className: 'wix-dropdown-panel' } );

    pages.forEach( function ( entry ) {
      var label = entry[ 0 ];
      var pageName = entry[ 1 ];
      var normalizedPage = pageName.replace( / /g, '_' );
      var isCurrent = ( normalizedPage === currentPage );
      var item;

      if ( isCurrent ) {
        item = wix.el( 'span', {
          className: 'wix-dropdown-item wix-dropdown-item--current',
          textContent: label,
          'aria-current': 'page'
        } );
      } else {
        item = wix.el( 'a', {
          className: 'wix-dropdown-item',
          textContent: label,
          href: mw.util.getUrl( pageName )
        } );
      }

      panel.appendChild( item );
    } );

    dropdown.appendChild( toggle );
    dropdown.appendChild( panel );

    // 4. Back / Next buttons
    var isFirst = currentIdx <= 0;
    var isLast  = currentIdx >= pages.length - 1;

    var btnBack = wix.el( 'a', {
      className: 'wix-dropdown-nav-btn'
    }, [ wix.el( 'span', { className: 'wix-dropdown-nav-arrow', textContent: '\u25BC' } ) ] );

    var btnNext = wix.el( 'a', {
      className: 'wix-dropdown-nav-btn'
    }, [ wix.el( 'span', { className: 'wix-dropdown-nav-arrow wix-dropdown-nav-arrow--next', textContent: '\u25BC' } ) ] );

    if ( isFirst || currentIdx === -1 ) {
      btnBack.classList.add( 'wix-dropdown-nav-btn--disabled' );
      btnBack.removeAttribute( 'href' );
    } else {
      btnBack.setAttribute( 'href', mw.util.getUrl( pages[ currentIdx - 1 ][ 1 ] ) );
    }

    if ( isLast || currentIdx === -1 ) {
      btnNext.classList.add( 'wix-dropdown-nav-btn--disabled' );
      btnNext.removeAttribute( 'href' );
    } else {
      btnNext.setAttribute( 'href', mw.util.getUrl( pages[ currentIdx + 1 ][ 1 ] ) );
    }

    // 5. Assemble: Back | Dropdown | Next
    var row = wix.el( 'div', { className: 'wix-dropdown-row' }, [
      btnBack,
      dropdown,
      btnNext
    ] );

    container.appendChild( row );

    // 6. Make nav buttons square (width = height, measured after layout)
    setTimeout( function () {
      var h = toggle.offsetHeight;
      if ( h ) {
        btnBack.style.width = h + 'px';
        btnNext.style.width = h + 'px';
      }
    }, 0 );

    // 7. Toggle open/close
    var isOpen = false;

    toggle.addEventListener( 'click', function () {
      isOpen = !isOpen;
      toggle.classList.toggle( 'wix-dropdown-toggle--open', isOpen );
      panel.classList.toggle( 'wix-dropdown-panel--open', isOpen );
    } );

    // 7. Close on click outside
    document.addEventListener( 'click', function ( e ) {
      if ( isOpen && !dropdown.contains( e.target ) ) {
        isOpen = false;
        toggle.classList.remove( 'wix-dropdown-toggle--open' );
        panel.classList.remove( 'wix-dropdown-panel--open' );
      }
    } );
  }


  /* ── Nav Cards init ────────────────────────────────────────────
     Reads data-wix-pages JSON:
       [["Label", "PageName", "Description", "icon-name"], ...]
     Builds a responsive grid of linked cards with SVG icons.
     ──────────────────────────────────────────────────────────── */

  function buildIconSvg( name ) {
    var paths = NAV_ICONS[ name ] || FALLBACK_ICON;
    return '<svg width="22" height="22" viewBox="0 0 28 28" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">' + paths + '</svg>';
  }

  function initNavCards( container ) {
    // 1. Read and parse page list
    var raw = wix.data( container, 'wix-pages', '[]' );
    var pages;
    try {
      pages = JSON.parse( raw );
    } catch ( e ) {
      return;
    }
    if ( !pages.length ) {
      return;
    }

    // 2. Build grid
    wix.empty( container );

    var grid = wix.el( 'div', {
      className: 'wix-nav-cards',
      'role': 'navigation',
      'aria-label': 'Page navigation'
    } );

    pages.forEach( function ( entry ) {
      var label    = entry[ 0 ];
      var pageName = entry[ 1 ];
      var desc     = entry[ 2 ] || '';
      var iconName = entry[ 3 ] || '';

      // Icon box
      var ico = wix.el( 'div', { className: 'wix-nav-card-ico' } );
      ico.innerHTML = buildIconSvg( iconName );

      // Text
      var nameEl = wix.el( 'div', { className: 'wix-nav-card-name', textContent: label } );
      var descEl = wix.el( 'div', { className: 'wix-nav-card-desc', textContent: desc } );
      var txt    = wix.el( 'div', { className: 'wix-nav-card-txt' }, [ nameEl, descEl ] );

      // Arrow
      var arrow = wix.el( 'div', { className: 'wix-nav-card-arrow' } );
      arrow.innerHTML = ARROW_SVG;

      // Card link
      var card = wix.el( 'a', {
        className: 'wix-nav-card',
        href: mw.util.getUrl( pageName )
      }, [ ico, txt, arrow ] );

      grid.appendChild( card );
    } );

    container.appendChild( grid );
  }

}() );