MediaWiki:Common.js: Difference between revisions

No edit summary
No edit summary
Line 1: Line 1:
// ── Load Sanscript.js first, then init everything ────────────────
(function () {
(function() {


   function loadScript(url, callback) {
   // ── 1. Load Sanscript from a reliable CDN ──────────────────────
    var s = document.createElement('script');
  var sanscriptReady = false;
    s.src = url;
  var s = document.createElement('script');
    s.onload = callback;
  s.src = 'https://cdn.jsdelivr.net/gh/sanskrit-coders/sanscript.js@master/sanscript.js';
    document.head.appendChild(s);
  s.onload = function () { sanscriptReady = true; };
  }
  document.head.appendChild(s);


   loadScript(
   // ── 2. Character maps ──────────────────────────────────────────
    'https://cdn.jsdelivr.net/npm/sanscript.js@1.1.2/sanscript.min.js',
    function() { initScriptSwitcher(); }
  );
 
  // ── Character maps for Kannada and Tamil ─────────────────────
   var SCRIPT_MAP = {
   var SCRIPT_MAP = {
     kn: {
     kn: {
Line 37: Line 31:
       'क':'க','ख':'க','ग':'க','घ':'க','ङ':'ங',
       'क':'க','ख':'க','ग':'க','घ':'க','ङ':'ங',
       'च':'ச','छ':'ச','ज':'ஜ','झ':'ஜ','ञ':'ஞ',
       'च':'ச','छ':'ச','ज':'ஜ','झ':'ஜ','ञ':'ஞ',
       'ट':'ட','ठ':'ட','ड':'ட','ढ':'ட','':'ண',
       'ट':'ட','ठ':'ட','ड':'ட','ढ':'ட','':'ண',
       'त':'த','थ':'த','द':'த','ध':'த','न':'ந',
       'त':'த','थ':'த','द':'த','ध':'த','न':'ந',
       'प':'ப','फ':'ப','ब':'ப','भ':'ப','म':'ம',
       'प':'ப','फ':'ப','ब':'ப','भ':'ப','म':'ம',
       'य':'ய','र':'ர','ल':'ல','व':'வ',
       'य':'ய','र':'ர','ल':'ல','व':'வ',
       'श':'ஶ','ष':'ஷ','स':'ஸ','ह':'ஹ',
       'श':'ஶ','ष':'ஷ','स':'ஸ','ह':'ஹ',
       'ा':'ா','ि':'ி','ी':'ீ','':'ு','ू':'ூ',
       'ा':'ா','ि':'ி','ी':'ீ','':'ு','ू':'ூ',
       'े':'ே','ै':'ை','ो':'ோ','ौ':'ௌ',
       'े':'ே','ै':'ை','ो':'ோ','ौ':'ௌ',
       'ं':'ம்','ः':':','्':'்','ॐ':'ௐ',
       'ं':'ம்','ः':':','्':'்','ॐ':'ௐ',
       '०':'0','१':'1','२':'2','३':'3','४':'4',
       '०':'0','१':'1','२':'2','३':'3','४':'4',
       '५':'5','६':'6','७':'7','':'8','९':'9'
       '५':'5','६':'6','७':'7','':'8','९':'9'
     }
     }
   };
   };


   var PRE_PROCESS = [
   var PRE = [
     [/ङ्क/g,'ंक'],[/ङ्ख/g,'ंख'],[/ङ्ग/g,'ंग'],[/ङ्घ/g,'ंघ'],
     [/ङ्क/g,'ंक'],[/ङ्ख/g,'ंख'],[/ङ्ग/g,'ंग'],[/ङ्घ/g,'ंघ'],
     [/ञ्च/g,'ंच'],[/ञ्ज/g,'ंज'],[/ण्ट/g,'ंट'],[/ण्ड/g,'ंड'],
     [/ञ्च/g,'ंच'],[/ञ्ज/g,'ंज'],[/ण्ट/g,'ंट'],[/ण्ड/g,'ंड'],
Line 56: Line 50:
   ];
   ];


   function preProcess(text) {
   function preProcess(t) {
     PRE_PROCESS.forEach(function(pair) {
     PRE.forEach(function (p) { t = t.replace(p[0], p[1]); });
      text = text.replace(pair[0], pair[1]);
     return t;
    });
     return text;
   }
   }


   function transliterateText(text, script) {
   function transliterateText(text, script) {
     if (script === 'en') {
     if (script === 'en') {
       return Sanscript.t(text, 'devanagari', 'iast');
       if (sanscriptReady && window.Sanscript) {
        return window.Sanscript.t(text, 'devanagari', 'iast');
      }
      return text;
     }
     }
     var map = SCRIPT_MAP[script];
     var map = SCRIPT_MAP[script];
     if (!map) return text;
     if (!map) return text;
    var processed = preProcess(text);
     return Array.from(preProcess(text)).map(function (ch) {
     return Array.from(processed).map(function(ch) {
       return map[ch] !== undefined ? map[ch] : ch;
       return map[ch] !== undefined ? map[ch] : ch;
     }).join('');
     }).join('');
Line 79: Line 73:
     if (!content) return;
     if (!content) return;


     // Restore original devanagari
     // Restore devanagari first
     content.querySelectorAll('[data-deva]').forEach(function(el) {
     content.querySelectorAll('[data-deva]').forEach(function (el) {
       el.textContent = el.getAttribute('data-deva');
       el.textContent = el.getAttribute('data-deva');
       el.removeAttribute('data-deva');
       el.removeAttribute('data-deva');
Line 86: Line 80:


     if (script === 'deva') return;
     if (script === 'deva') return;
    // If English but Sanscript not ready, retry after short delay
    if (script === 'en' && (!sanscriptReady || !window.Sanscript)) {
      setTimeout(function () { applyScript('en'); }, 300);
      return;
    }


     var walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT);
     var walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT);
Line 91: Line 91:
     while (walker.nextNode()) nodes.push(walker.currentNode);
     while (walker.nextNode()) nodes.push(walker.currentNode);


     nodes.forEach(function(node) {
     nodes.forEach(function (node) {
      var p = node.parentNode;
      if (!p) return;
      // Skip switcher bar, TOC, and edit links
      if (p.closest) {
        if (p.closest('.gr-script-bar') ||
            p.closest('.vector-toc') ||
            p.closest('#toc') ||
            p.closest('.mw-editsection')) return;
      }
       var orig = node.textContent;
       var orig = node.textContent;
       var trans = transliterateText(orig, script);
       var trans = transliterateText(orig, script);
Line 98: Line 107:
         span.setAttribute('data-deva', orig);
         span.setAttribute('data-deva', orig);
         span.textContent = trans;
         span.textContent = trans;
         node.parentNode.replaceChild(span, node);
         p.replaceChild(span, node);
       }
       }
     });
     });
   }
   }


   function initScriptSwitcher() {
  // ── 3. Build switcher bar ──────────────────────────────────────
     mw.hook('wikipage.content').add(function() {
   function buildBar() {
      // Only add on doc pages (pages with gr-doc-title)
     var title = document.querySelector('.gr-doc-title');
      var title = document.querySelector('.gr-doc-title');
    if (!title) return;
      if (!title) return;
    if (document.querySelector('.gr-script-bar')) return;


      var bar = document.createElement('div');
    var bar = document.createElement('div');
      bar.className = 'gr-script-bar';
    bar.className = 'gr-script-bar';
      bar.innerHTML =
    bar.innerHTML =
        '<span class="gr-script-label">change script to</span>' +
      '<span class="gr-script-label">change script to</span>' +
        '<a class="gr-script-btn active" data-script="deva">देवनागरी</a>' +
      '<a class="gr-script-btn active" data-script="deva">देवनागरी</a>' +
        '<a class="gr-script-btn" data-script="kn">ಕನ್ನಡ</a>' +
      '<a class="gr-script-btn" data-script="kn">ಕನ್ನಡ</a>' +
        '<a class="gr-script-btn" data-script="ta">தமிழ்</a>' +
      '<a class="gr-script-btn" data-script="ta">தமிழ்</a>' +
        '<a class="gr-script-btn" data-script="en">English</a>';
      '<a class="gr-script-btn" data-script="en">English</a>';


      title.after(bar);
    title.after(bar);


      bar.querySelectorAll('.gr-script-btn').forEach(function(btn) {
    bar.querySelectorAll('.gr-script-btn').forEach(function (btn) {
        btn.addEventListener('click', function(e) {
      btn.addEventListener('click', function (e) {
          e.preventDefault();
        e.preventDefault();
          bar.querySelectorAll('.gr-script-btn').forEach(function(b) {
        bar.querySelectorAll('.gr-script-btn').forEach(function (b) {
            b.classList.remove('active');
          b.classList.remove('active');
          });
          btn.classList.add('active');
          applyScript(btn.getAttribute('data-script'));
         });
         });
        btn.classList.add('active');
        applyScript(btn.getAttribute('data-script'));
       });
       });
     });
     });
  }
  // Run on DOMContentLoaded to ensure bar persists on refresh
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', buildBar);
  } else {
    buildBar();
  }
  // Also hook MW dynamic loads
  if (window.mw) {
    mw.hook('wikipage.content').add(function () {
      setTimeout(buildBar, 150);
    });
  }
  // ── 4. TOC active highlight via MutationObserver ───────────────
  // Watches class changes on TOC list items so highlight works
  // universally on all pages, not just BS.
  function watchTocActive() {
    var toc = document.querySelector('.vector-toc');
    if (!toc) return;
    var observer = new MutationObserver(function (mutations) {
      mutations.forEach(function (m) {
        if (m.type !== 'attributes' || m.attributeName !== 'class') return;
        var li = m.target;
        var link = li.querySelector(':scope > .vector-toc-link');
        if (!link) return;
        if (li.classList.contains('vector-toc-list-item-active')) {
          link.style.color = '#f57c00';
          link.style.fontWeight = '700';
        } else {
          link.style.color = '';
          link.style.fontWeight = '';
        }
      });
    });
    toc.querySelectorAll('.vector-toc-list-item').forEach(function (li) {
      observer.observe(li, { attributes: true, attributeFilter: ['class'] });
    });
  }
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', watchTocActive);
  } else {
    watchTocActive();
   }
   }


})();
})();