MediaWiki:Common.js: Difference between revisions

From Sanatan Hindu Dharma
No edit summary
Tag: Reverted
No edit summary
Tag: Reverted
Line 1,537: Line 1,537:
   })(jQuery);
   })(jQuery);
});
});




Line 1,545: Line 1,546:


// -----------------------------------------------------------
// -----------------------------------------------------------
// Internal Link Suggestions for VisualEditor (ES5 Compatible)
// Internal Link Suggestions for VisualEditor (MW 1.39, ES5)
// Works for MediaWiki 1.39.10 - Real VE Link Node Insertion
// With Toggle Button + Real VE Link Node Insertion
// -----------------------------------------------------------
// -----------------------------------------------------------


Line 1,571: Line 1,572:
             btn.style.borderRadius = "4px";
             btn.style.borderRadius = "4px";
             btn.style.cursor = "pointer";
             btn.style.cursor = "pointer";
             btn.style.background = "#f8f8f8";
             btn.style.background = "#f0f0f0";


             btn.onclick = function () {
             btn.onclick = function () {
                 var box = document.getElementById('ve-link-suggest-box');
                 var box = document.getElementById('ve-link-suggest-box');
                 if (box.style.display === "none") {
                 box.style.display = (box.style.display === "none") ? "block" : "none";
                    box.style.display = "block";
                } else {
                    box.style.display = "none";
                }
             };
             };


Line 1,586: Line 1,583:


         // ---------------------------------------------------
         // ---------------------------------------------------
         // 2. Create Sidebar Panel (Hidden by Default)
         // 2. Create the Suggestions Box (Hidden by Default)
         // ---------------------------------------------------
         // ---------------------------------------------------


Line 1,616: Line 1,613:


         // ---------------------------------------------------
         // ---------------------------------------------------
         // 3. VE Text Reading + Suggestions (ES5 safe)
         // 3. Extract ONLY the typed content (ignore footer)
        // ---------------------------------------------------
 
        function getUserText() {
            var editable = document.querySelector('.ve-ce-documentNode .ve-ce-contentBranchNode');
            if (!editable) return "";
 
            var nodes = editable.querySelectorAll('p, h1, h2, h3, h4, h5, h6');
            var text = "";
 
            for (var i = 0; i < nodes.length; i++) {
                text += " " + nodes[i].innerText;
            }
 
            return text.replace(/\s+/g, " ").trim();
        }
 
        // ---------------------------------------------------
        // 4. Suggestion Engine
         // ---------------------------------------------------
         // ---------------------------------------------------


Line 1,625: Line 1,640:
         model.on("change", function () {
         model.on("change", function () {


            // Do nothing when panel closed
             if (sidebar.style.display === "none") return;
             if (sidebar.style.display === "none") return;


Line 1,634: Line 1,648:
             debounceTimer = setTimeout(function () {
             debounceTimer = setTimeout(function () {


                 var text = "";
                 var text = getUserText();
                try {
                 if (!text) {
                    text = model.getDocument().data.getText();
                     resultBox.innerHTML = "Type something…";
                } catch (err) {
                    text = "";
                }
 
                 if (!text || text.trim().length < 2) {
                     resultBox.innerHTML = "Keep typing...";
                     return;
                     return;
                 }
                 }


                 var words = text.split(/\s+/);
                 var words = text.split(" ");
                 var query = words.slice(-5).join(" ");
                 var query = words.slice(-5).join(" ");


Line 1,681: Line 1,689:
                         })(results[i]);
                         })(results[i]);
                     }
                     }
                 });
                 });


Line 1,688: Line 1,695:


         // ---------------------------------------------------
         // ---------------------------------------------------
         // 4. REAL VE LINK INSERTION (BLUE LINK) — ES5 SAFE
         // 5. Insert REAL VE LINK NODE
         // ---------------------------------------------------
         // ---------------------------------------------------


Line 1,700: Line 1,707:
                     {
                     {
                         type: 'link',
                         type: 'link',
                         attributes: {
                         attributes: { href: mw.util.getUrl(title) }
                            href: mw.util.getUrl(title)
                        }
                     },
                     },
                     title,
                     title,
Line 1,716: Line 1,721:


         // ---------------------------------------------------
         // ---------------------------------------------------
         // 5. FINAL FALLBACK (execCommand)
         // 6. Fallback for older browsers
         // ---------------------------------------------------
         // ---------------------------------------------------


Line 1,724: Line 1,729:
                 editable.focus();
                 editable.focus();
                 document.execCommand('insertText', false, "[[" + title + "]]");
                 document.execCommand('insertText', false, "[[" + title + "]]");
                 mw.notify("Inserted (fallback): " + title);
                 mw.notify("Inserted using fallback");
             } catch (e) {
             } catch (e) {
                 mw.notify("Insert failed!", { type: "error" });
                 mw.notify("Insert failed!", { type: "error" });

Revision as of 12:08, 20 November 2025


mw.loader.using('mediawiki.util').done(function () {
    console.log("Common.js loaded safely");
});


/* Any JavaScript here will be loaded for all users on every page load. */

/*

document.addEventListener("DOMContentLoaded", function() {
  const btn = document.querySelector(".toggle-btn");
  const content = document.querySelector(".toggle-content");

  if (btn && content) {
    btn.addEventListener("click", function() {
      content.style.display = (content.style.display === "block") ? "none" : "block";
    });
  }
});


// Auto-add parent category when editing/creating a subpage
( function () {
    if ( mw.config.get('wgAction') !== 'edit' ) return;

    // wgTitle contains title without namespace, e.g. "Ancient-education/Subpage"
    var title = mw.config.get('wgTitle') || '';
    if ( title.indexOf('/') === -1 ) return; // not a subpage

    var parent = title.split('/')[0]; // "Ancient-education"

    // jQuery available
    $( function () {
        var textarea = $('#wpTextbox1');
        if ( !textarea.length ) return;

        // Only append if not present
        var current = textarea.val() || '';
        var catTag = '\n[[Category:' + parent + ']]';
        if ( current.indexOf(catTag.trim()) === -1 ) {
            // Insert the category at the end of the text area (preserve existing text)
            textarea.val(current + catTag);
        }
    } );
}() );

$(document).ready(function () {
  // Skip special pages
  if (mw.config.get('wgNamespaceNumber') < 0) return;

  var $content = $('#mw-content-text');

  // Fetch all page titles from the API (main namespace only)
  $.get(mw.util.wikiScript('api'), {
    action: 'query',
    list: 'allpages',
    aplimit: 'max',
    format: 'json'
  }).done(function (data) {
    var titles = data.query.allpages.map(function (p) { return p.title; });

    var html = $content.html();
    titles.forEach(function (title) {
      // Safe regex for whole words
      var safeTitle = title.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
      var regex = new RegExp('\\b(' + safeTitle + ')\\b', 'g');
      html = html.replace(regex, '<a href="/wiki/' + encodeURIComponent(title.replace(/ /g, '_')) + '">$1</a>');
    });

    $content.html(html);
  });
});






$(document).ready(function() {
    if (mw.config.get('wgNamespaceNumber') >= 0) { // Only show on normal pages
        var pageName = mw.config.get('wgPageName');
        var uploadUrl = mw.util.getUrl('Form:UploadVideo', { 'page': pageName });

        $('<div style="position:fixed; bottom:20px; right:20px; background:#007bff; color:white; padding:10px; border-radius:5px; cursor:pointer; font-weight:bold;">Upload a Video</div>')
        .click(function() {
            window.location.href = uploadUrl;
        }).appendTo('body');
    }
});
 */


/* Start Pushkar Code */

$('img').attr('loading', 'lazy');

mw.loader.using(['jquery'], function () {
  // Load Slick dynamically
  $.getScript('https://cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js')
    .done(function () {
      $(function () {
        // Initialize Slick after content loads
       $('.adsBannerSliderHero ').not('.slick-initialized').slick({
          slidesToShow: 1,
          slidesToScroll: 1,
          autoplay: true,
          autoplaySpeed: 3000,
          dots: false,
          arrows: true,
          prevArrow: '<button class="prev-arrow"><i class="fas fa-chevron-left"></i></button>',
          nextArrow: '<button class="next-arrow"><i class="fas fa-chevron-right"></i></button>',
          //adaptiveHeight: true
        });

       $('.sanatanWisdomSlider').not('.slick-initialized').slick({
          slidesToShow: 3,
          slidesToScroll: 1,
          autoplay: true,
          autoplaySpeed: 3000,
          dots: false,
          arrows: true,
          prevArrow: '<button class="prev-arrow"><i class="fas fa-chevron-left"></i></button>',
          nextArrow: '<button class="next-arrow"><i class="fas fa-chevron-right"></i></button>',
          responsive: [
                       {breakpoint: 768, settings: {arrows: false, centerMode: true, slidesToShow: 2 }},
                       {breakpoint: 480, settings: { arrows: false,slidesToShow: 1}}
                      ],
          adaptiveHeight: true
        });

        $('.latestArticlesSlider').not('.slick-initialized').slick({
         slidesToShow: 3,
          slidesToScroll: 1,
          autoplay: true,
          autoplaySpeed: 3000,
          dots: false,
          arrows: false,
          variableWidth: true,
          prevArrow: '<button class="prev-arrow"><i class="fas fa-chevron-left"></i></button>',
          nextArrow: '<button class="next-arrow"><i class="fas fa-chevron-right"></i></button>',
          responsive: [
                       {breakpoint: 768, settings: {arrows: false, centerMode: true, slidesToShow: 2 }},
                       {breakpoint: 480, settings: { arrows: false,slidesToShow: 1}}
                      ],
          adaptiveHeight: true
        });


      });
    })
    .fail(function () {
      console.error('Failed to load Slick Slider JS');
    });
});

/* End Pushkar Code */





/* Functions of Slider One */

(function () {
  function initSliders() {
    var sliders = document.querySelectorAll('.mw-slider');
    sliders.forEach(function (slider) {
      // Avoid double-init
      if (slider._mwSliderInited) return;
      slider._mwSliderInited = true;

      var viewport = slider.querySelector('.mw-slider-viewport');
      var track = slider.querySelector('.mw-slider-track');
      var items = Array.from(slider.querySelectorAll('.mw-slider-item'));
      var btnPrev = slider.querySelector('.mw-slider-btn.prev');
      var btnNext = slider.querySelector('.mw-slider-btn.next');

      var currentIndex = 0;
      var itemsToShow = getItemsToShow();
      var gap = parseFloat(getComputedStyle(track).columnGap || getComputedStyle(track).gap || 16);

      function getItemsToShow() {
        var w = window.innerWidth;
        if (w <= 600) return 1;
        if (w <= 900) return 2;
        return 3;
      }

      function updateSizes() {
        itemsToShow = getItemsToShow();
        // compute single item width including gap
        if (!items[0]) return;
        var itemRect = items[0].getBoundingClientRect();
        gap = parseFloat(getComputedStyle(track).columnGap || getComputedStyle(track).gap || 16);
        var single = itemRect.width + gap;
        // ensure currentIndex in range
        var maxIndex = Math.max(0, items.length - itemsToShow);
        currentIndex = Math.min(currentIndex, maxIndex);
        // apply transform
        var translateX = -currentIndex * single;
        track.style.transform = 'translateX(' + translateX + 'px)';
        updateButtons();
      }

      function updateButtons() {
        var maxIndex = Math.max(0, items.length - itemsToShow);
        if (btnPrev) btnPrev.disabled = currentIndex <= 0;
        if (btnNext) btnNext.disabled = currentIndex >= maxIndex;
      }

      function gotoIndex(index) {
        var maxIndex = Math.max(0, items.length - itemsToShow);
        currentIndex = Math.max(0, Math.min(maxIndex, index));
        updateSizes();
      }

      if (btnPrev) btnPrev.addEventListener('click', function () {
        gotoIndex(currentIndex - 1);
      });
      if (btnNext) btnNext.addEventListener('click', function () {
        gotoIndex(currentIndex + 1);
      });

      // Keyboard support
      slider.addEventListener('keydown', function (e) {
        if (e.key === 'ArrowLeft') gotoIndex(currentIndex - 1);
        if (e.key === 'ArrowRight') gotoIndex(currentIndex + 1);
      });

      // Resize handling
      var resizeTimeout;
      window.addEventListener('resize', function () {
        clearTimeout(resizeTimeout);
        resizeTimeout = setTimeout(updateSizes, 120);
      });

      // Touch / drag support
      (function () {
        var startX = 0;
        var currentTranslate = 0;
        var dragging = false;
        var pointerId = null;

        function pointerDown(e) {
          if (e.pointerType === 'mouse' && e.button !== 0) return;
          dragging = true;
          pointerId = e.pointerId;
          startX = e.clientX;
          track.style.transition = 'none';
          track.setPointerCapture && track.setPointerCapture(pointerId);
        }

        function pointerMove(e) {
          if (!dragging || e.pointerId !== pointerId) return;
          var dx = e.clientX - startX;
          var itemRect = items[0] && items[0].getBoundingClientRect();
          var single = itemRect ? (itemRect.width + gap) : 0;
          var baseTranslate = -currentIndex * single;
          track.style.transform = 'translateX(' + (baseTranslate + dx) + 'px)';
        }

        function pointerUp(e) {
          if (!dragging || e.pointerId !== pointerId) return;
          dragging = false;
          track.style.transition = '';
          var dx = e.clientX - startX;
          var threshold = Math.max(40, (items[0] ? items[0].getBoundingClientRect().width : 200) * 0.15);
          if (dx > threshold) {
            gotoIndex(currentIndex - 1);
          } else if (dx < -threshold) {
            gotoIndex(currentIndex + 1);
          } else {
            updateSizes();
          }
          try { track.releasePointerCapture(pointerId); } catch (err) {}
          pointerId = null;
        }

        track.addEventListener('pointerdown', pointerDown);
        window.addEventListener('pointermove', pointerMove);
        window.addEventListener('pointerup', pointerUp);
        track.addEventListener('pointercancel', pointerUp);
      })();

      // Initial sizes
      setTimeout(updateSizes, 60);
    });
  }

  // init on DOM ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', initSliders);
  } else {
    initSliders();
  }

  // If new content is loaded via AJAX on the wiki, re-init
  if (window.mw && mw.hook) {
    mw.hook('wikipage.content').add(initSliders);
  }
})();

/* Full width Slider */
(function () {
  function initFullSliders() {
    var sliders = document.querySelectorAll('.mw-fullslider');
    sliders.forEach(function (slider) {
      if (slider._fullSliderInit) return;
      slider._fullSliderInit = true;

      var track = slider.querySelector('.mw-fullslider-track');
      var slides = Array.from(track.children);
      var btnPrev = slider.querySelector('.mw-fullslider-btn.prev');
      var btnNext = slider.querySelector('.mw-fullslider-btn.next');
      var dots = Array.from(slider.querySelectorAll('.mw-fullslider-dots .dot'));

      var current = 0;
      var slideCount = slides.length;

      function goTo(index, animate) {
        current = (index % slideCount + slideCount) % slideCount;
        var x = -current * slider.clientWidth;
        if (animate === false) track.style.transition = 'none';
        else track.style.transition = '';
        track.style.transform = 'translateX(' + x + 'px)';
        updateControls();
        if (animate === false) {
          // force reflow then restore
          void track.offsetWidth;
          track.style.transition = '';
        }
      }

      function updateControls() {
        if (btnPrev) btnPrev.disabled = false;
        if (btnNext) btnNext.disabled = false;
        // update dots
        dots.forEach(function (d) {
          d.classList.toggle('active', +d.getAttribute('data-index') === current);
          d.setAttribute('aria-pressed', (+d.getAttribute('data-index') === current).toString());
        });
      }

      if (btnPrev) btnPrev.addEventListener('click', function () { goTo(current - 1); });
      if (btnNext) btnNext.addEventListener('click', function () { goTo(current + 1); });

      dots.forEach(function (dot) {
        dot.addEventListener('click', function () {
          var idx = parseInt(this.getAttribute('data-index'), 10);
          goTo(idx);
        });
      });

      // Resize handling: ensure slide width matches viewport
      var resizeTimer;
      function onResize() {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(function () {
          // Recompute translate in case width changed
          goTo(current, false);
        }, 80);
      }
      window.addEventListener('resize', onResize);

      // Touch / drag support
      (function () {
        var startX = 0, startTranslate = 0, dragging = false, pointerId = null;
        function down(e) {
          if (e.pointerType === 'mouse' && e.button !== 0) return;
          dragging = true;
          pointerId = e.pointerId;
          startX = e.clientX;
          var style = window.getComputedStyle(track);
          var matrix = new WebKitCSSMatrix(style.transform);
          startTranslate = matrix.m41 || 0;
          track.style.transition = 'none';
          e.target.setPointerCapture && e.target.setPointerCapture(pointerId);
        }
        function move(e) {
          if (!dragging || e.pointerId !== pointerId) return;
          var dx = e.clientX - startX;
          track.style.transform = 'translateX(' + (startTranslate + dx) + 'px)';
        }
        function up(e) {
          if (!dragging || e.pointerId !== pointerId) return;
          dragging = false;
          track.style.transition = '';
          var dx = e.clientX - startX;
          var threshold = Math.max(40, slider.clientWidth * 0.12);
          if (dx > threshold) goTo(current - 1);
          else if (dx < -threshold) goTo(current + 1);
          else goTo(current);
          try { e.target.releasePointerCapture(pointerId); } catch (err) {}
          pointerId = null;
        }
        track.addEventListener('pointerdown', down);
        window.addEventListener('pointermove', move);
        window.addEventListener('pointerup', up);
        track.addEventListener('pointercancel', up);
      })();

      // Autoplay (optional): change interval or set autoplay = false
      var autoplay = true;
      var autoplayInterval = 4500; // ms
      var autoplayTimer = null;
      function startAutoplay() {
        if (!autoplay) return;
        stopAutoplay();
        autoplayTimer = setInterval(function () { goTo(current + 1); }, autoplayInterval);
      }
      function stopAutoplay() {
        if (autoplayTimer) { clearInterval(autoplayTimer); autoplayTimer = null; }
      }
      slider.addEventListener('mouseenter', stopAutoplay);
      slider.addEventListener('mouseleave', startAutoplay);
      slider.addEventListener('focusin', stopAutoplay);
      slider.addEventListener('focusout', startAutoplay);

      // Respect prefers-reduced-motion
      var rmq = window.matchMedia('(prefers-reduced-motion: reduce)');
      if (rmq.matches) autoplay = false;

      // Ensure initial sizing: make each slide exactly slider.clientWidth
      function layoutSlides() {
        var w = slider.clientWidth;
        slides.forEach(function (s) { s.style.minWidth = w + 'px'; s.style.maxWidth = w + 'px'; });
        goTo(current, false);
      }

      // Wait for images then layout
      function imgsReady(cb) {
        var imgs = Array.from(slider.querySelectorAll('img'));
        var rem = imgs.length;
        if (!rem) return cb();
        imgs.forEach(function (img) {
          if (img.complete) { rem--; if (!rem) cb(); }
          else {
            img.addEventListener('load', function () { rem--; if (!rem) cb(); });
            img.addEventListener('error', function () { rem--; if (!rem) cb(); });
          }
        });
      }

      imgsReady(function () {
        layoutSlides();
        startAutoplay();
        window.addEventListener('resize', onResize);
      });

      // expose for debug (optional)
      slider._goTo = goTo;
    });
  }

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initFullSliders);
  else initFullSliders();

  if (window.mw && mw.hook) mw.hook('wikipage.content').add(initFullSliders);
})();





 




// --- Disable Tools Option for all users except admin ---

mw.loader.using(['mediawiki.user'], function () {
    $(function () {
        mw.user.getGroups().then(function (groups) {
            // If the user is NOT an admin (sysop)
            if (groups.indexOf('sysop') === -1) {

                // Disable Tools menu and its dropdown items
                $('a, span').filter(function () {
                    return $(this).text().trim() === 'Tools';
                }).each(function () {
                    const link = $(this);
                    link.css({
                        'pointer-events': 'none',
                        'opacity': '0',
                        'cursor': 'not-allowed',
                        'width' : '1px',
                        'height' : '1px',
                        'display' : 'none',
                    });
                    link.attr('title', 'Restricted to admins');
                    link.closest('.dropdown').find('a').css({
                        'pointer-events': 'none',
                        'opacity': '0.5',
                        'cursor': 'not-allowed'
                    });
                });


                // Disable Tools menu and its dropdown items
                $('a, span').filter(function () {
                    return $(this).text().trim() === 'उपकरण';
                }).each(function () {
                    const link = $(this);
                    link.css({
                        'pointer-events': 'none',
                        'opacity': '0',
                        'cursor': 'not-allowed',
                        'width' : '1px',
                        'height' : '1px',
                        'display' : 'none',
                    });
                    link.attr('title', 'Restricted to admins');
                    link.closest('.dropdown').find('a').css({
                        'pointer-events': 'none',
                        'opacity': '0.5',
                        'cursor': 'not-allowed'
                    });
                });

                // Disable any link to Special:SpecialPages
                $('a[href*="Special:SpecialPages"]').css({
                    'pointer-events': 'none',
                    'opacity': '0.5',
                    'cursor': 'not-allowed'
                }).attr('title', 'Restricted to admins');

                // Disable MediaWiki namespace links
                $('a[href*="MediaWiki:"]').css({
                    'pointer-events': 'none',
                    'opacity': '0.5',
                    'cursor': 'not-allowed'
                }).attr('title', 'Restricted to admins');
            }
        });
    });
});

// Collapsible Related Pages on Mobile
mw.loader.using('jquery', function () {
  $(function () {
    var header = $('.page-links-header');
    var content = $('.page-links-content');

    if (header.length && content.length) {
      header.on('click', function () {
        $(this).toggleClass('active');
        content.toggleClass('open');
      });
    }
  });
});








































(function () {
    mw.loader.using(['ext.visualEditor.desktopArticleTarget.init', 'oojs-ui', 'jquery']).done(function () {

        /* --------------------------------------------------
            Add "SEO" button to VisualEditor toolbar
        -------------------------------------------------- */
        if (mw.config.get('wgIsArticle')) {
            mw.hook('ve.activationComplete').add(function () {
                try {
                    var veTarget = ve.init && ve.init.target;
                    var toolbar = veTarget && veTarget.toolbar;
                    if (!toolbar) return;
                    if (toolbar.$element.find('.ve-ui-toolbar-seoButton').length) return;

                    var seoButton = new OO.ui.ButtonWidget({
                        label: 'SEO',
                        icon: 'settings',
                        classes: ['ve-ui-toolbar-seoButton']
                    });

                    seoButton.on('click', function () {
                        openSEODialog(veTarget);
                    });

                    toolbar.$element.find('.oo-ui-toolbar-actions').append(seoButton.$element);

                } catch (e) {
                    console.error('[SEO] Toolbar init error:', e);
                }
            });
        }

        /* --------------------------------------------------
             SEO Dialog definition
        -------------------------------------------------- */
        function openSEODialog(veTarget) {

            var surface = veTarget.surface;
            var model = surface.getModel();
            var docText = '';

            try {
                docText = model.getDocument().data.getText(true);
console.log("DOC TEXT =", docText);
            } catch (e) {
                var txt = document.getElementById('wpTextbox1');
                if (txt) docText = txt.value;
            }

            /* ===================================================================
                ADDED BLOCK: Extract SEO from VisualEditor COMMENT nodes ⭐
               =================================================================== */

                  var oldTitle = '', oldDesc = '', oldKeys = '';

var match = /<!--\s*SEO\s+title=(.*?)\s+description=([\s\S]*?)\s+keywords=([\s\S]*?)\s*-->/i.exec(docText);

if (match) {
    oldTitle = match[1].trim();
    oldDesc  = match[2].trim();
    oldKeys  = match[3].trim();
}

        /* ===================================================================
                DO NOT USE OLD REGEX — VE hides comments in comment nodes ⭐
               =================================================================== */

            // Input fields (your original code)
            var titleInput = new OO.ui.TextInputWidget({ placeholder: 'Meta Title', value: oldTitle });
            var descInput = new OO.ui.MultilineTextInputWidget({ placeholder: 'Meta Description', rows: 3, value: oldDesc });
            var keysInput = new OO.ui.TextInputWidget({ placeholder: 'Meta Keywords', value: oldKeys });

            // Define dialog (your original code)
            var SEODialog = function (cfg) { SEODialog.super.call(this, cfg); };
            OO.inheritClass(SEODialog, OO.ui.ProcessDialog);
            SEODialog.static.name = 'seoDialog';
            SEODialog.static.title = 'SEO Settings';
            SEODialog.static.size = 'larger';
            SEODialog.static.actions = [
                { action: 'save', label: 'Save', flags: ['primary', 'progressive'] },
                { action: 'cancel', label: 'Cancel', flags: ['safe'] }
            ];

            SEODialog.prototype.initialize = function () {
                SEODialog.super.prototype.initialize.apply(this, arguments);

                var panel = new OO.ui.PanelLayout({ padded: true, expanded: true });
                panel.$element.append(
                    $('<label>').text('Meta Title'),
                    titleInput.$element,
                    $('<br><label>').text('Meta Description'),
                    descInput.$element,
                    $('<br><label>').text('Meta Keywords'),
                    keysInput.$element
                );
                this.$body.append(panel.$element);
            };

            SEODialog.prototype.getBodyHeight = function () {
                return 420;
            };

            /* --------------------------------------------------
               Save / Cancel buttons
            -------------------------------------------------- */
            SEODialog.prototype.getActionProcess = function (action) {
                var dialog = this;

                if (action === 'save') {
                    return new OO.ui.Process(function () {

                        var t = titleInput.getValue().trim();
                        var d = descInput.getValue().trim();
                        var k = keysInput.getValue().trim();

                        var newSEOComment =
                            '<!--SEO ' +
                            'title=' + mw.html.escape(t) + ' ' +
                            'description=' + mw.html.escape(d) + ' ' +
                            'keywords=' + mw.html.escape(k) +
                            ' -->\n';

                        var newText = docText.replace(/<!--SEO[\s\S]*?-->/i, '');
                        newText = newSEOComment + newText;

                        try {
                            var docLen = model.getDocument().data.getLength();
                            model.getLinearFragment(new ve.Range(0, docLen)).insertContent(newText);
                            mw.notify('✔️ SEO data saved.');
                        } catch (err) {
                            var ta = document.querySelector('textarea#wpTextbox1');
                            if (ta) ta.value = newText;
                            mw.notify('✔️ SEO data saved (fallback).');
                        }

                        dialog.close({ action: 'cancel' });
                    });
                }

                if (action === 'cancel') {
                    return new OO.ui.Process(function () {
                        dialog.close({ action: 'cancel' });
                    });
                }

                return SEODialog.super.prototype.getActionProcess.call(this, action);
            };

            // Window manager (your original code)
            var wm = window._seoWM || new OO.ui.WindowManager();
            if (!window._seoWM) {
                window._seoWM = wm;
                $(document.body).append(wm.$element);
            }

            var dlg = new SEODialog();
            wm.addWindows([dlg]);
            wm.openWindow(dlg);
        }
    });
})();


 








// == Showing Template as default footer

$(document).ready(function () {

  // Remove Chameleon’s default footer
  $('.footercontainer, #footer, #mw-footer').remove();

  // Prevent duplicate inserts
  if ($('#mw-custom-footer').length) return;

  // --- Detect Hindi language ---

  var pathParts = window.location.pathname.split('/').filter(Boolean);
  var isHindi = pathParts.length > 0 && pathParts[0].toLowerCase() === 'hi';

  // Choose template
  var templateName = isHindi ? 'Custom-footer-Hindi' : 'Custom-footer';

  // Load chosen footer
  $.ajax({
    url: '/index.php?title=Template:' + templateName + '&action=render',
    type: 'GET',
    success: function (data) {
      const footer = $('<div id="mw-custom-footer"></div>').html(data);
      $('body').append(footer);
    },
    error: function () {
      console.warn('⚠️ Custom footer could not be loaded.');
    }
  });

});






// == Parent page logic when create new pages and category logic ==

mw.loader.using(['mediawiki.util', 'mediawiki.api']).then(function () {
    const api = new mw.Api();
    const username = mw.config.get('wgUserName');
    if (!username) return;

    const wgNamespace = mw.config.get('wgNamespaceNumber');
    const wgTitle = mw.config.get('wgTitle');
    const wgPageName = mw.config.get('wgPageName');
    const wgAction = mw.config.get('wgAction');
    const wgCurRevisionId = mw.config.get('wgCurRevisionId');

    const urlParams = new URLSearchParams(window.location.search);
    const autoCat = urlParams.get('autocategory');
    const skipParent = urlParams.get('skipparent');

    /* ---------------- Category Prompt ---------------- */
    if (wgNamespace === 14) { // Category namespace
        const storageKey = 'category_prompt_done_' + wgTitle;

        function askAndCreate() {
            if (sessionStorage.getItem(storageKey)) return;
            sessionStorage.setItem(storageKey, 'done');

            const ask = confirm(
                '✅ You just created the new category "' + wgTitle + '".\n\nDo you want to create a normal page with the same name? It will automatically belong to this category.'
            );

            if (ask) {
                const editUrl = mw.util.getUrl(wgTitle, {
                    action: 'edit',
                    veaction: 'edit',
                    autocategory: wgTitle,
                    skipparent: 1 // skip parent prompt
                });
                window.location.href = editUrl;
            }
        }

        mw.hook('postEdit').add(askAndCreate);
        $(window).on('popstate', function () {
            if (wgAction !== 'view') return;
            if (sessionStorage.getItem(storageKey)) return;

            api.get({
                action: 'query',
                titles: 'Category:' + wgTitle,
                prop: 'info',
                format: 'json'
            }).done(function (data) {
                const pageData = Object.values(data.query.pages)[0];
                if (pageData && pageData.missing === undefined) {
                    askAndCreate();
                }
            });
        });
    }

    /* ---------------- Inject Category ---------------- */
    function injectCategory(category) {
        if (!category) return;
        const textarea = $('#wpTextbox1');
        if (textarea.length && !textarea.val().includes('[[' + 'Category:' + category + ']]')) {
            textarea.val('[[' + 'Category:' + category + ']]\n\n' + textarea.val());
        }
    }

    if (autoCat) {
        $(document).ready(function () { injectCategory(autoCat); });
        mw.hook('ve.activationComplete').add(function () { injectCategory(autoCat); });
    }

    /* ---------------- Reminder Banner ---------------- */
    mw.hook('wikipage.content').add(function ($content) {
        if (wgAction === 'edit' || wgAction === 'submit') {
            const banner = $('<div>')
                .css({
                    background: '#fff8c4',
                    border: '1px solid #e0c14b',
                    padding: '10px',
                    marginBottom: '10px',
                    borderRadius: '6px',
                    textAlign: 'center',
                    fontWeight: '600'
                })
                .text('🪶 Tip: Remember to set a parent page before saving.');
            $content.prepend(banner);
        }
    });

    /* ---------------- Parent Page Prompt ---------------- */
    function askForParent(title, callback) {
        if (window.parentPromptShown) return;
        window.parentPromptShown = true;

        const overlay = $('<div>').css({
            position: 'fixed', top: 0, left: 0, width: '100%', height: '100%',
            background: 'rgba(0,0,0,0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center',
            zIndex: 999999
        });

        const box = $('<div>').css({
            background: '#fff', padding: '20px', borderRadius: '10px',
            width: '400px', textAlign: 'center', boxShadow: '0 4px 10px rgba(0,0,0,0.3)'
        });

        box.append('<h3>Select the Category</h3>');

        const input = $('<input type="text" placeholder="Type to search existing pages...">').css({
            width: '100%', padding: '8px', border: '1px solid #ccc', borderRadius: '5px'
        });

        const suggestionBox = $('<ul>').css({
            listStyle: 'none', margin: '10px 0 0', padding: 0,
            maxHeight: '150px', overflowY: 'auto', border: '1px solid #ddd',
            borderRadius: '5px', display: 'none', textAlign: 'left'
        });

        const confirmBtn = $('<button>Confirm</button>').css({
            marginTop: '10px', background: '#007bff', color: '#fff',
            border: 'none', padding: '8px 14px', borderRadius: '5px', cursor: 'pointer'
        });

        const skipBtn = $('<button>No Category</button>').css({
            marginLeft: '8px', marginTop: '10px', background: '#6c757d', color: '#fff',
            border: 'none', padding: '8px 14px', borderRadius: '5px', cursor: 'pointer'
        });

        box.append(input, suggestionBox, $('<div>').append(confirmBtn, skipBtn));
        overlay.append(box);
        $('body').append(overlay);

        // Autocomplete
        input.on('input', function () {
            const query = input.val().trim();
            suggestionBox.empty();
            if (query.length < 2) { suggestionBox.hide(); return; }

            api.get({
                action: 'opensearch',
                search: query,
                limit: 8,
                namespace: 0
            }).done(function (data) {
                const results = data[1] || [];
                suggestionBox.empty();
                if (results.length) {
                    suggestionBox.show();
                    results.forEach(function (page) {
                        $('<li>').text(page).css({padding:'6px 10px', cursor:'pointer'})
                            .hover(
                                function(){ $(this).css('background','#f0f0f0'); },
                                function(){ $(this).css('background',''); }
                            ).click(function(){ input.val(page); suggestionBox.hide(); })
                            .appendTo(suggestionBox);
                    });
                } else { suggestionBox.hide(); }
            });
        });

        confirmBtn.on('click', function () {
            const parent = input.val().trim();
            if (!parent) { alert('Please select or type a parent page name, or click "No Parent".'); return; }
            const newTitle = parent + '/' + title;
            overlay.remove();
            if (callback) callback(newTitle);
        });

        skipBtn.on('click', function () {
            overlay.remove();
            if (callback) callback(title);
        });

        overlay.on('click', function(e){ if(e.target===overlay[0]) alert('Please choose a parent or click "No Parent".'); });
    }

    /* ---------------- Handle New Page ---------------- */
    function handleNewPage() {
        if (wgNamespace !== 0 || wgAction !== 'edit' || wgCurRevisionId !== 0) return;

        if (skipParent && autoCat) {
            // Skip parent, inject category
            mw.hook('ve.activationComplete').add(function(){ injectCategory(autoCat); });
            $(document).ready(function(){ injectCategory(autoCat); });
        } else {
            // Normal parent prompt
            askForParent(wgPageName, function(newTitle){
                const editUrl = mw.util.getUrl(newTitle, {veaction:'edit', autocategory:autoCat || undefined});
                if(window.location.href !== editUrl) window.location.href = editUrl;
            });
        }
    }

    if (wgAction === 'edit') handleNewPage();
    mw.hook('ve.activationComplete').add(handleNewPage);

    console.log(" Complete Category + Parent Page workflow loaded.");
});










// Page create UI for Writers / Leads / Editors (ES5 Safe)
(function () {
    try {
        if (document.readyState === 'complete' || document.readyState === 'interactive') {
            initCreateButton();
        } else {
            document.addEventListener('DOMContentLoaded', initCreateButton);
        }

        function initCreateButton() {
            try {
                if (typeof mw === 'undefined' || !mw.config) return;
                if (!mw.config.exists('wgUserName') || !mw.config.get('wgUserName')) return;

                var groups = mw.config.get('wgUserGroups') || [];
                var isWriter = groups.indexOf('writer') !== -1;
                var isLead = groups.indexOf('lead') !== -1;
                var isEditor = groups.indexOf('editor') !== -1;
                var isAdmin = groups.indexOf('sysop') !== -1;

                // Popup allowed only for these users
                if (!(isWriter || isLead || isEditor || isAdmin)) return;

                if (document.getElementById('floatingCreateBtn')) return;

                // Floating button
                var btn = document.createElement('button');
                btn.id = 'floatingCreateBtn';
                btn.appendChild(document.createTextNode('+'));
                btn.style.position = 'fixed';
                btn.style.bottom = '30px';
                btn.style.right = '30px';
                btn.style.width = '60px';
                btn.style.height = '60px';
                btn.style.borderRadius = '50%';
                btn.style.background = '#0078D7';
                btn.style.color = '#fff';
                btn.style.fontSize = '32px';
                btn.style.border = 'none';
                btn.style.cursor = 'pointer';
                btn.style.zIndex = '9999';
                btn.style.boxShadow = '0 4px 10px rgba(0,0,0,0.3)';

                btn.addEventListener('mouseover', function () {
                    btn.style.background = '#005fa3';
                });
                btn.addEventListener('mouseout', function () {
                    btn.style.background = '#0078D7';
                });

                document.body.appendChild(btn);

                // Popup box
                var popup = document.createElement('div');
                popup.id = 'createPopupBox';
                popup.style.position = 'fixed';
                popup.style.bottom = '100px';
                popup.style.right = '30px';
                popup.style.background = '#fff';
                popup.style.border = '2px solid #ccc';
                popup.style.borderRadius = '12px';
                popup.style.padding = '15px';
                popup.style.width = '260px';
                popup.style.display = 'none';
                popup.style.boxShadow = '0 6px 14px rgba(0,0,0,0.25)';
                popup.style.zIndex = '10000';

                // Main HTML
                var html = '';
                html += '<label style="font-weight:bold;">Select Language</label><br>';
                html += '<select id="pageLang" style="width:100%;padding:6px;margin:6px 0;border:1px solid #ccc;border-radius:5px;">';
                html += '<option value="en">English</option>';
                html += '<option value="hi">Hindi</option>';
                html += '</select>';

                html += '<label style="font-weight:bold;">Create new page</label><br>';
                html += '<input type="text" id="newPageName" placeholder="Enter page name" style="width:100%;padding:6px;margin-top:4px;border:1px solid #ccc;border-radius:5px;">';

                html += '<button id="createPageBtn" style="margin-top:8px;width:100%;background:#0078D7;color:white;border:none;padding:6px;border-radius:6px;cursor:pointer;">Create Page</button>';

                // CATEGORY — only for Editor + Admin
                if (isEditor || isAdmin) {
                    html += '<hr style="margin:10px 0;">';
                    html += '<label style="font-weight:bold;">Create new category</label><br>';
                    html += '<input type="text" id="newCategoryName" placeholder="Enter category name" style="width:100%;padding:6px;margin-top:4px;border:1px solid #ccc;border-radius:5px;">';

                    html += '<button id="createCategoryBtn" style="margin-top:8px;width:100%;background:#28a745;color:white;border:none;padding:6px;border-radius:6px;cursor:pointer;">Create Category</button>';
                }

                // Add HTML to popup
                popup.innerHTML = html;
                document.body.appendChild(popup);

                // ⭐ SIMPLE + GUARANTEED BUTTON INSERT ⭐
                // Add Dashboard + Mapping for everyone who can see the popup
                var btnContainer = document.createElement('div');
                btnContainer.innerHTML =
                    '<hr style="margin:10px 0;">' +
                    '<button id="openDashboardBtn" style="margin-top:8px;width:100%;background:#6f42c1;color:#fff;border:none;padding:6px;border-radius:6px;cursor:pointer;">Dashboard</button>' +
                    '<button id="openMappingBtn" style="margin-top:6px;width:100%;background:#ff5733;color:#fff;border:none;padding:6px;border-radius:6px;cursor:pointer;">Mapping</button>';

                popup.appendChild(btnContainer);

                // Toggle popup
                btn.addEventListener('click', function () {
                    popup.style.display = popup.style.display === 'none' ? 'block' : 'none';
                });

                // Delegated events (click handling)
                popup.addEventListener('click', function (ev) {
                    var target = ev.target;

                    // Create Page
                    if (target.id === 'createPageBtn') {
                        var langSel = document.getElementById('pageLang').value;
                        var name = document.getElementById('newPageName').value.replace(/^\s+|\s+$/g, '');
                        if (!name) {
                            alert('Please enter a page name');
                            return;
                        }

                        var title = name.replace(/\s+/g, '_');
                        var pageUrl = (langSel === 'hi')
                            ? '/hi/' + title + '?action=edit&veaction=edit'
                            : '/' + title + '?action=edit&veaction=edit';

                        window.location.href = pageUrl;
                    }

                    // Create Category
                    if (target.id === 'createCategoryBtn') {
                        var cat = document.getElementById('newCategoryName').value.replace(/^\s+|\s+$/g, '');
                        if (!cat) {
                            alert('Please enter a category name');
                            return;
                        }

                        var cTitle = 'Category:' + cat.replace(/\s+/g, '-');
                        window.location.href = '/' + cTitle + '?action=edit&veaction=edit';
                    }

                    // Dashboard
                    if (target.id === 'openDashboardBtn') {
                        window.location.href = 'https://sanatanhindudharma.org/Special:TeamDashboard';
                    }

                    // Mapping
                    if (target.id === 'openMappingBtn') {
                        window.location.href = 'https://sanatanhindudharma.org/Special:TeamMapping';
                    }
                });

            } catch (eInner) {
                console.error('CreateButton init error:', eInner);
            }
        }

    } catch (e) {
        console.error('CreateButton outer error:', e);
    }
})();





// Team Dashboard Settings 

mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function () {
  (function ($) {
    /** ---------- Utility: escape HTML ---------- **/
    function escapeHtml(str) {
      return String(str)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');
    }

    /** ---------- Detect TeamDashboard ---------- **/
    var pageName = mw.config.get('wgCanonicalSpecialPageName') || '';
    if (String(pageName).toLowerCase() !== 'teamdashboard') return;

    /** ---------- Accordion UI ---------- **/
   /** ---------- Accordion UI ---------- **/
function initAccordionOnce() {
  $('.accordion-toggle').each(function () {
    var $el = $(this);
    var targetSel = $el.attr('data-target');
    var $target = $(targetSel);
    if (!$target.length) return;

    // Ensure arrow exists
    if ($el.find('.pa-arrow').length === 0) {
      $el.prepend('<span class="pa-arrow">▶</span> ');
    }

    var saved = localStorage.getItem('pa:' + targetSel);

    // ----- Restore open/closed state -----
    if (saved === 'open') {
      $target.show();
      $el.addClass('open'); // <<< IMPORTANT: Add open class
      $el.find('.pa-arrow').text('▼ ');
    } else {
      $target.hide();
      $el.removeClass('open');
      $el.find('.pa-arrow').text('▶ ');
    }

    // ----- Attach click handler once -----
    if (!$el.data('pa-bound')) {
      $el.on('click', function () {
        var isOpen = $el.hasClass('open');

        if (isOpen) {
          // close
          $el.removeClass('open');
          $target.slideUp(150);
          $el.find('.pa-arrow').text('▶ ');
          localStorage.setItem('pa:' + targetSel, 'closed');
        } else {
          // open
          $el.addClass('open');
          $target.slideDown(150);
          $el.find('.pa-arrow').text('▼ ');
          localStorage.setItem('pa:' + targetSel, 'open');
        }
      });

      $el.data('pa-bound', true);
    }
  });
}


    /** ---------- MediaWiki API ---------- **/
    var api = new mw.Api();
    function getFreshToken() {
      return api
        .get({
          action: 'query',
          meta: 'tokens',
          type: 'csrf',
          format: 'json'
        })
        .then(function (d) {
          return d.query.tokens.csrftoken || '';
        })
        .catch(function () {
          return '';
        });
    }

    /** ---------- POST helper ---------- **/
    function postAction(fd) {
      return $.ajax({
        url: mw.util.getUrl('Special:TeamDashboard'),
        type: 'POST',
        data: fd,
        processData: false,
        contentType: false,
        headers: { 'X-Requested-With': 'XMLHttpRequest' }
      });
    }

    /** ---------- Approve / Reject / Forward ---------- **/
    $(document).on('click', 'button[data-action]', function (e) {
      e.preventDefault();
      var $btn = $(this);
      if ($btn.prop('disabled')) return;

      var action = $btn.data('action'),
        pageId = $btn.data('page-id');

      $btn.prop('disabled', true);

      getFreshToken().then(function (token) {
        if (!token) {
          alert('Session expired, reload.');
          $btn.prop('disabled', false);
          return;
        }

        var fd = new FormData();
        fd.append('pa_action', action);
        fd.append('page_id', pageId);
        fd.append('token', token);

        if (action === 'forward') {
          var txt = $.trim($btn.closest('td').find('input.comment-input').val() || '');
          if (txt !== '') fd.append('comment', txt);
        }

        postAction(fd)
          .done(function () {
            if (action === 'approve') {
              $btn.text('Approved ✓').prop('disabled', true);
              $btn.closest('td').prev().prev().text('approved');
            } else if (action === 'reject') {
              $btn.text('Rejected ✗').prop('disabled', true);
              $btn.closest('td').prev().prev().text('rejected');
            } else if (action === 'forward') {
              $btn.text('Forwarded ➜').prop('disabled', true);
            }
          })
          .fail(function () {
            alert('Action failed. Please try again.');
            $btn.prop('disabled', false);
          });
      });
    });

    /** ---------- Comment submit ---------- **/
    $(document).on('click', '.comment-submit', function (e) {
      e.preventDefault();
      var $btn = $(this);
      if ($btn.prop('disabled')) return;

      var $wrap = $btn.closest('.ajax-comment-wrap'),
        txt = $.trim($wrap.find('input.comment-input').val() || ''),
        pageId = $btn.data('page-id');

      if (txt === '') return;
      $btn.prop('disabled', true);

      getFreshToken().then(function (token) {
        if (!token) {
          alert('Session expired, reload.');
          $btn.prop('disabled', false);
          return;
        }

        var fd = new FormData();
        fd.append('pa_action', 'comment');
        fd.append('page_id', pageId);
        fd.append('token', token);
        fd.append('comment', txt);

        postAction(fd)
          .done(function (resp) {
            var $td = $btn.closest('td');
            var $list = $td.find('.comment-list');
            if (!$list.length) {
              var box = $('<div class="comment-box"><b>Comments</b><ul class="comment-list"></ul></div>');
              $td.append(box);
              $list = box.find('.comment-list');
            }

            var username = mw.config.get('wgUserName') || 'You';
            var now = new Date();
            var istOffset = 5.5 * 60 * 60 * 1000; // UTC+5:30
            var ist = new Date(now.getTime() + istOffset);
            var timestamp =
              ist.getFullYear() +
              '-' +
              String(ist.getMonth() + 1).padStart(2, '0') +
              '-' +
              String(ist.getDate()).padStart(2, '0') +
              ' ' +
              String(ist.getHours()).padStart(2, '0') +
              ':' +
              String(ist.getMinutes()).padStart(2, '0') +
              ':' +
              String(ist.getSeconds()).padStart(2, '0');

            var li = $('<li/>').html(
              '<b>' +
                escapeHtml(username) +
                '</b> <span class="date">(' +
                timestamp +
                ' IST)</span><br>' +
                escapeHtml(txt) +
                ' <button class="edit-comment-btn">✏️</button>'
            );
            $list.prepend(li);
            $wrap.find('input.comment-input').val('');
          })
          .fail(function () {
            alert('Could not add comment. Try again.');
          })
          .always(function () {
            $btn.prop('disabled', false);
          });
      });
    });

    /** ---------- Enter key submits comment ---------- **/
    $(document).on('keypress', 'input.comment-input', function (e) {
      if (e.which === 13) {
        e.preventDefault();
        $(this).closest('.ajax-comment-wrap').find('.comment-submit').trigger('click');
      }
    });

    /** ---------- Delete comment ---------- **/
    $(document).on('click', '.delete-comment-btn', function (e) {
      e.preventDefault();
      var $btn = $(this);
      if ($btn.prop('disabled')) return;
      if (!confirm('Delete this comment?')) return;

      var commentId = $btn.data('comment-id'),
        pageId = $btn.data('page-id');

      $btn.prop('disabled', true);

      getFreshToken().then(function (token) {
        if (!token) {
          alert('Session expired.');
          $btn.prop('disabled', false);
          return;
        }

        var fd = new FormData();
        fd.append('pa_action', 'delete_comment');
        fd.append('comment_id', commentId);
        fd.append('page_id', pageId);
        fd.append('token', token);

        postAction(fd)
          .done(function () {
            $btn.closest('li').fadeOut(200, function () {
              $(this).remove();
            });
          })
          .fail(function () {
            alert('Delete failed.');
          })
          .always(function () {
            $btn.prop('disabled', false);
          });
      });
    });

    /** ---------- ✏️ Edit comment (new feature) ---------- **/
    $(document).on('click', '.edit-comment-btn', function () {
      var $btn = $(this);
      var $li = $btn.closest('li');
      var oldText = $li
        .clone()
        .children()
        .remove()
        .end()
        .text()
        .trim();

      var pageId = $li.closest('td').find('.comment-submit').data('page-id');
      var commentId = $btn.data('comment-id');

      if ($li.find('.edit-comment-area').length) return;

      var $area = $('<textarea class="edit-comment-area"></textarea>').val(oldText);
      var $save = $('<button class="pa-btn save-edit">Save</button>');
      var $cancel = $('<button class="pa-btn danger cancel-edit">Cancel</button>');
      $li.append($area, $save, $cancel);

      $save.on('click', function () {
        var newText = $.trim($area.val());
        if (!newText) return alert('Comment cannot be empty.');

        getFreshToken().then(function (token) {
          var fd = new FormData();
          fd.append('pa_action', 'edit_comment');
          fd.append('comment_id', commentId);
          fd.append('page_id', pageId);
          fd.append('comment', newText);
          fd.append('token', token);

          postAction(fd)
            .done(function (resp) {
              if (resp.ok) {
                $area.remove();
                $save.remove();
                $cancel.remove();
                $btn.before(' ' + escapeHtml(newText) + ' <em>(edited)</em> ');
              } else {
                alert(resp.error || 'Edit failed.');
              }
            })
            .fail(function () {
              alert('Edit failed.');
            });
        });
      });

      $cancel.on('click', function () {
        $area.remove();
        $save.remove();
        $cancel.remove();
      });
    });
  /** ---------- Global Search (Leads, Writers, Articles) ---------- **/
$(document).on('input', '.pa-search', function () {
    var q = $(this).val().toLowerCase();

    // Filter table rows (articles)
    $('.dashboard-table tbody tr').each(function () {
        $(this).toggle($(this).text().toLowerCase().indexOf(q) !== -1);
    });

    // Filter accordion headers (lead names, writer names)
    $('.accordion-item').each(function () {
        var txt = $(this).text().toLowerCase();
        var match = txt.indexOf(q) !== -1;

        $(this).toggle(match);
    });
});


    /** ---------- Search Filter ---------- **/
    $(document).on('input', '.search-input', function () {
      var q = $(this).val().toLowerCase();
      $('.dashboard-table tbody tr').each(function () {
        var t = $(this).text().toLowerCase();
        $(this).toggle(t.indexOf(q) !== -1);
      });
    });

    /** ---------- Init ---------- **/
    initAccordionOnce();
    setTimeout(initAccordionOnce, 700);
  })(jQuery);
});








// -----------------------------------------------------------
// Internal Link Suggestions for VisualEditor (MW 1.39, ES5)
// With Toggle Button + Real VE Link Node Insertion
// -----------------------------------------------------------

mw.loader.using(['ext.visualEditor.desktopArticleTarget']).then(function () {

    mw.hook('ve.activationComplete').add(function () {

        // ---------------------------------------------------
        // 1. Add Toggle Button in VE Toolbar (ES5 safe)
        // ---------------------------------------------------

        function addToggleButton() {
            var toolbar = document.querySelector('.ve-ui-toolbar');
            if (!toolbar) return;

            if (document.getElementById('ve-link-toggle-btn')) return;

            var btn = document.createElement('button');
            btn.id = 've-link-toggle-btn';
            btn.innerHTML = "Links";
            btn.style.marginLeft = "8px";
            btn.style.padding = "4px 10px";
            btn.style.border = "1px solid #ccc";
            btn.style.borderRadius = "4px";
            btn.style.cursor = "pointer";
            btn.style.background = "#f0f0f0";

            btn.onclick = function () {
                var box = document.getElementById('ve-link-suggest-box');
                box.style.display = (box.style.display === "none") ? "block" : "none";
            };

            toolbar.appendChild(btn);
        }

        // ---------------------------------------------------
        // 2. Create the Suggestions Box (Hidden by Default)
        // ---------------------------------------------------

        var sidebar = document.createElement('div');
        sidebar.id = "ve-link-suggest-box";
        sidebar.style.position = "fixed";
        sidebar.style.top = "90px";
        sidebar.style.right = "20px";
        sidebar.style.width = "260px";
        sidebar.style.maxHeight = "400px";
        sidebar.style.overflowY = "auto";
        sidebar.style.background = "#ffffff";
        sidebar.style.border = "1px solid #ccc";
        sidebar.style.padding = "10px";
        sidebar.style.borderRadius = "6px";
        sidebar.style.boxShadow = "0 2px 6px rgba(0,0,0,0.2)";
        sidebar.style.zIndex = "9999";
        sidebar.style.display = "none";

        sidebar.innerHTML =
            '<b>Suggested Links</b>' +
            '<hr style="margin:6px 0;">' +
            '<div id="ve-suggest-results">Click "Links" to open.</div>';

        document.body.appendChild(sidebar);
        addToggleButton();

        var resultBox = document.getElementById('ve-suggest-results');

        // ---------------------------------------------------
        // 3. Extract ONLY the typed content (ignore footer)
        // ---------------------------------------------------

        function getUserText() {
            var editable = document.querySelector('.ve-ce-documentNode .ve-ce-contentBranchNode');
            if (!editable) return "";

            var nodes = editable.querySelectorAll('p, h1, h2, h3, h4, h5, h6');
            var text = "";

            for (var i = 0; i < nodes.length; i++) {
                text += " " + nodes[i].innerText;
            }

            return text.replace(/\s+/g, " ").trim();
        }

        // ---------------------------------------------------
        // 4. Suggestion Engine
        // ---------------------------------------------------

        var surface = ve.init.target.getSurface();
        var model = surface.getModel();
        var debounceTimer = null;

        model.on("change", function () {

            if (sidebar.style.display === "none") return;

            if (debounceTimer) {
                clearTimeout(debounceTimer);
            }

            debounceTimer = setTimeout(function () {

                var text = getUserText();
                if (!text) {
                    resultBox.innerHTML = "Type something…";
                    return;
                }

                var words = text.split(" ");
                var query = words.slice(-5).join(" ");

                new mw.Api().get({
                    action: "query",
                    list: "search",
                    srsearch: query,
                    srlimit: 6,
                    format: "json"
                }).done(function (data) {

                    var results = (data && data.query && data.query.search) ? data.query.search : [];

                    if (!results.length) {
                        resultBox.innerHTML = "No suggestions found.";
                        return;
                    }

                    resultBox.innerHTML = "";

                    for (var i = 0; i < results.length; i++) {
                        (function (row) {
                            var item = document.createElement('div');
                            item.style.padding = "6px";
                            item.style.cursor = "pointer";
                            item.style.borderBottom = "1px solid #eee";
                            item.innerHTML = row.title;

                            item.onclick = function () {
                                insertRealLink(row.title);
                            };

                            resultBox.appendChild(item);
                        })(results[i]);
                    }
                });

            }, 350);
        });

        // ---------------------------------------------------
        // 5. Insert REAL VE LINK NODE
        // ---------------------------------------------------

        function insertRealLink(title) {
            try {
                var surface = ve.init.target.getSurface();
                var model = surface.getModel();
                var fragment = model.getFragment();

                fragment.insertContent([
                    {
                        type: 'link',
                        attributes: { href: mw.util.getUrl(title) }
                    },
                    title,
                    { type: '/link' }
                ]);

                mw.notify("Inserted: " + title);

            } catch (e) {
                fallbackInsert(title);
            }
        }

        // ---------------------------------------------------
        // 6. Fallback for older browsers
        // ---------------------------------------------------

        function fallbackInsert(title) {
            try {
                var editable = document.querySelector('[contenteditable="true"]');
                editable.focus();
                document.execCommand('insertText', false, "[[" + title + "]]");
                mw.notify("Inserted using fallback");
            } catch (e) {
                mw.notify("Insert failed!", { type: "error" });
            }
        }

    });

});