MediaWiki:Common.js: Difference between revisions
From Sanatan Hindu Dharma
No edit summary |
No edit summary |
||
| Line 1,028: | Line 1,028: | ||
(function ($) { | (function ($) { | ||
$(function () { | $(function () { | ||
/ | |||
/** ---------- Small HTML escape ---------- **/ | |||
function escapeHtml(str) { | function escapeHtml(str) { | ||
return String(str) | return String(str) | ||
| Line 1,038: | Line 1,039: | ||
} | } | ||
/ | /** ---------- Detect Special:TeamDashboard ---------- **/ | ||
var pageName = null; | var pageName = null; | ||
try { | try { | ||
| Line 1,044: | Line 1,045: | ||
pageName = mw.config.get('wgCanonicalSpecialPageName') || mw.config.get('wgPageName'); | pageName = mw.config.get('wgCanonicalSpecialPageName') || mw.config.get('wgPageName'); | ||
} | } | ||
} catch (e) { | } catch (e) {} | ||
if (!pageName) { | if (!pageName) { | ||
var path = (location.pathname || '').toLowerCase(); | var path = (location.pathname || '').toLowerCase(); | ||
if (path. | if (path.includes('/special:teamdashboard') || path.includes('title=special:teamdashboard')) { | ||
pageName = 'TeamDashboard'; | pageName = 'TeamDashboard'; | ||
} else if ((document.title || '').toLowerCase(). | } else if ((document.title || '').toLowerCase().includes('team dashboard')) { | ||
pageName = 'TeamDashboard'; | pageName = 'TeamDashboard'; | ||
} | } | ||
} | } | ||
if (!pageName || String(pageName).indexOf('TeamDashboard') === -1) return; | |||
/** ---------- Accordion Logic ---------- **/ | |||
/* ---------- | |||
function initAccordionOnce() { | function initAccordionOnce() { | ||
$('.accordion-toggle').each(function () { | $('.accordion-toggle').each(function () { | ||
| Line 1,068: | Line 1,066: | ||
if (!$target.length) return; | if (!$target.length) return; | ||
if ($el.find('.pa-arrow').length === 0) { | if ($el.find('.pa-arrow').length === 0) { | ||
$el.prepend('<span class="pa-arrow">▶ </span>'); | $el.prepend('<span class="pa-arrow">▶ </span>'); | ||
} | } | ||
try { | try { | ||
var saved = localStorage.getItem('pa:' + targetSel); | var saved = localStorage.getItem('pa:' + targetSel); | ||
| Line 1,083: | Line 1,079: | ||
$el.find('.pa-arrow').text('▶ '); | $el.find('.pa-arrow').text('▶ '); | ||
} | } | ||
} catch (err) { | } catch (err) {} | ||
if (!$el.data('pa-bound')) { | if (!$el.data('pa-bound')) { | ||
$el.on('click', function () { | $el.on('click', function () { | ||
| Line 1,102: | Line 1,095: | ||
} | } | ||
/* ---------- AJAX | /** ---------- Get fresh CSRF token ---------- **/ | ||
function getFreshToken(callback) { | |||
$.get(mw.util.wikiScript('api'), { | |||
action: 'query', | |||
meta: 'tokens', | |||
type: 'csrf', | |||
format: 'json' | |||
}).done(function (data) { | |||
if (data?.query?.tokens?.csrftoken) { | |||
callback(data.query.tokens.csrftoken); | |||
} else { | |||
callback(''); | |||
} | |||
}).fail(function () { | |||
callback(''); | |||
}); | |||
} | |||
/** ---------- AJAX Helper ---------- **/ | |||
function postAction(fd, onSuccess, onError) { | function postAction(fd, onSuccess, onError) { | ||
$.ajax({ | $.ajax({ | ||
| Line 1,118: | Line 1,129: | ||
} | } | ||
/* ---------- | /** ---------- Approve / Reject / Forward ---------- **/ | ||
$(document).on('click', 'button[data-action]', function (e) { | $(document).on('click', 'button[data-action]', function (e) { | ||
e.preventDefault(); | e.preventDefault(); | ||
| Line 1,125: | Line 1,136: | ||
var action = $btn.data('action'); | var action = $btn.data('action'); | ||
var pageId = $btn.data('page-id'); | var pageId = $btn.data('page-id'); | ||
$btn.prop('disabled', true); | |||
$btn.prop('disabled', | // Get fresh CSRF token | ||
getFreshToken(function (token) { | |||
if (!token) { | |||
alert('Session expired. Please reload.'); | |||
$btn.prop('disabled', false); | |||
return; | |||
} | |||
var fd = new FormData(); | |||
fd.append('action', action); | |||
fd.append('page_id', pageId); | |||
fd.append('token', token); | |||
if (action === 'forward') { | |||
var $input = $btn.closest('td').find('input.comment-input'); | |||
if ($input.length) { | |||
var v = $.trim($input.val()); | |||
if (v !== '') fd.append('comment', v); | |||
} | |||
} | } | ||
postAction(fd, function () { | |||
// optimistic UI | |||
if (action === 'approve') { | |||
$btn.text('Approved ✓').addClass('disabled').prop('disabled', true); | |||
$btn.closest('td').prev().prev().text('approved'); | |||
$btn.closest('td').find('.comment-box').remove(); | |||
} else if (action === 'reject') { | |||
$btn.text('Rejected ✗').addClass('disabled').prop('disabled', true); | |||
$btn.closest('td').prev().prev().text('rejected'); | |||
} else if (action === 'forward') { | |||
$btn.text('Forwarded ➜').addClass('disabled').prop('disabled', true); | |||
} | |||
$btn.prop('disabled', false); | |||
}, function () { | |||
$btn.prop('disabled', false); | |||
alert('Action failed. Please try again.'); | |||
}); | |||
}); | }); | ||
}); | }); | ||
/* ---------- | /** ---------- Comment Submit ---------- **/ | ||
$(document).on('click', '.comment-submit', function (e) { | $(document).on('click', '.comment-submit', function (e) { | ||
e.preventDefault(); | e.preventDefault(); | ||
var $btn = $(this); | var $btn = $(this); | ||
if ($btn.prop('disabled')) return; | if ($btn.prop('disabled')) return; | ||
var $wrap = $btn.closest('.ajax-comment-wrap'); | var $wrap = $btn.closest('.ajax-comment-wrap'); | ||
var $input = $wrap.find('input.comment-input'); | var $input = $wrap.find('input.comment-input'); | ||
var txt = $.trim($input.val()); | var txt = $.trim($input.val()); | ||
if (txt === '') return; | if (txt === '') return; | ||
var pageId = $btn.data('page-id'); | |||
$btn.prop('disabled', true); | $btn.prop('disabled', true); | ||
getFreshToken(function (token) { | |||
if (!token) { | |||
alert('Session expired. Please reload the page.'); | |||
$btn.prop('disabled', false); | |||
if (! | return; | ||
$ | |||
} | } | ||
var li = $('<li/>').html('<b>You</b> <span class="date">(just now)</span><br/>' + escapeHtml(txt)); | |||
var fd = new FormData(); | |||
fd.append('action', 'comment'); | |||
fd.append('page_id', pageId); | |||
fd.append('token', token); | |||
fd.append('comment', txt); | |||
postAction(fd, function () { | |||
var $td = $btn.closest('td'); | |||
var $list = $td.find('.comment-list'); | |||
if (!$list.length) { | |||
var $cb = $('<div class="comment-box"><b>Comments</b><ul class="comment-list"></ul></div>'); | |||
$td.append($cb); | |||
$list = $cb.find('.comment-list'); | |||
} | |||
var li = $('<li/>').html('<b>You</b> <span class="date">(just now)</span><br/>' + escapeHtml(txt)); | |||
$list.prepend(li); | |||
$input.val(''); | |||
$btn.prop('disabled', false); | |||
}, function () { | |||
$btn.prop('disabled', false); | |||
alert('Could not add comment. Please try again.'); | |||
}); | |||
}); | }); | ||
}); | }); | ||
// | // Enter key submit | ||
$(document).on('keypress', 'input.comment-input', function (e) { | $(document).on('keypress', 'input.comment-input', function (e) { | ||
if (e.which === 13) { | if (e.which === 13) { | ||
| Line 1,214: | Line 1,232: | ||
}); | }); | ||
/* ---------- | /** ---------- Delete Comment ---------- **/ | ||
$(document).on('click', '.delete-comment-btn', function (e) { | $(document).on('click', '.delete-comment-btn', function (e) { | ||
e.preventDefault(); | e.preventDefault(); | ||
| Line 1,222: | Line 1,240: | ||
var commentId = $btn.data('comment-id'); | var commentId = $btn.data('comment-id'); | ||
var pageId = $btn.data('page-id'); | var pageId = $btn.data('page-id'); | ||
$btn.prop('disabled', true); | |||
getFreshToken(function (token) { | |||
if (!token) { | |||
alert('Session expired. Please reload.'); | |||
$btn.prop('disabled', false); | |||
return; | |||
} | |||
var fd = new FormData(); | |||
fd.append('action', 'delete_comment'); | |||
fd.append('comment_id', commentId); | |||
fd.append('page_id', pageId); | |||
fd.append('token', token); | |||
postAction(fd, function () { | |||
$btn.closest('li').remove(); | |||
}, function () { | |||
$btn.prop('disabled', false); | |||
alert('Could not delete comment. Try again.'); | |||
}); | |||
}); | }); | ||
}); | }); | ||
/* ---------- | /** ---------- Client-side Search ---------- **/ | ||
$(document).on('input', '.search-input', function () { | $(document).on('input', '.search-input', function () { | ||
var q = $.trim($(this).val()).toLowerCase(); | var q = $.trim($(this).val()).toLowerCase(); | ||
| Line 1,247: | Line 1,271: | ||
if (!$table.length) $table = $('.dashboard-table').first(); | if (!$table.length) $table = $('.dashboard-table').first(); | ||
$table.find('tbody tr').each(function () { | $table.find('tbody tr').each(function () { | ||
var | var text = $(this).text().toLowerCase(); | ||
$(this).toggle(text.indexOf(q) !== -1); | |||
}); | }); | ||
}); | }); | ||
/* ---------- Prevent | /** ---------- Prevent accidental native submits ---------- **/ | ||
$('form').each(function () { | $('form').each(function () { | ||
var $f = $(this); | var $f = $(this); | ||
| Line 1,265: | Line 1,286: | ||
}); | }); | ||
// | // init accordions | ||
initAccordionOnce(); | initAccordionOnce(); | ||
setTimeout(initAccordionOnce, 700); | setTimeout(initAccordionOnce, 700); | ||
}); | }); | ||
})(jQuery); | })(jQuery); | ||
Revision as of 08:26, 10 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 */
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.5',
'cursor': 'not-allowed'
});
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');
});
}
});
});
/* === Auto-Link Page Titles in Paragraphs (exclude header/footer) === */
(function (mw, $) {
'use strict';
var MAX_TITLES = 1000;
function escapeRegExp(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function run(titles) {
if (!titles || titles.length === 0) return;
var filtered = titles
.filter(function (t) {
return t && t.length > 3;
})
.sort(function (a, b) {
return b.length - a.length;
})
.slice(0, MAX_TITLES);
// Select only main content paragraphs (not header/footer)
$('#content p').each(function () {
if ($(this).find('a, code, pre, .no-auto-link').length) return;
var html = $(this).html();
filtered.forEach(function (title) {
var display = title.includes(':')
? title.split(':').pop()
: title;
var pattern = display.replace(/[_-]+/g, '[ _-]');
var re = new RegExp('\\b' + escapeRegExp(pattern) + '\\b', 'gi');
html = html.replace(re, function (match) {
return (
'<a href="' +
mw.util.getUrl(title) +
'" class="auto-linked-page">' +
match +
'</a>'
);
});
});
$(this).html(html);
});
}
$(function () {
var title = mw.config.get('wgPageName');
if (!title) return;
$.getJSON(
mw.util.wikiScript() +
'?title=Special:AutoLinkTitles&format=json&pageTitle=' +
encodeURIComponent(title)
)
.done(function (data) {
if (data && Array.isArray(data.titles)) {
run(data.titles);
}
})
.fail(function () {
console.warn('AutoLinkTitles: failed to load title list.');
});
});
})(mediaWiki, jQuery);
// == 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;
// Load your custom footer
$.ajax({
url: '/index.php?title=Template:Custom-footer&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 Parent Page</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 Parent</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.");
});
// Safe ES5 Floating "+" create UI for Writers / Leads / Editors
(function () {
try {
// Run after DOM ready
if (document.readyState === 'complete' || document.readyState === 'interactive') {
initCreateButton();
} else {
document.addEventListener('DOMContentLoaded', initCreateButton);
}
function initCreateButton() {
try {
// Guard: ensure mw exists
if (typeof mw === 'undefined' || !mw.config) {
return;
}
// Only for logged-in users
if (!mw.config.exists('wgUserName') || !mw.config.get('wgUserName')) {
return;
}
var groups = mw.config.get('wgUserGroups') || [];
var isWriter = indexOf(groups, 'writer') !== -1;
var isLead = indexOf(groups, 'lead') !== -1;
var isEditor = indexOf(groups, 'editor') !== -1;
// Only show for writer/lead/editor
if (!(isWriter || isLead || isEditor)) {
return;
}
// Prevent duplicates
if (document.getElementById('floatingCreateBtn')) {
return;
}
// Create button element
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)';
// hover
btn.addEventListener('mouseover', function () { btn.style.background = '#005fa3'; });
btn.addEventListener('mouseout', function () { btn.style.background = '#0078D7'; });
document.body.appendChild(btn);
// Create popup container
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.boxShadow = '0 6px 14px rgba(0,0,0,0.25)';
popup.style.display = 'none';
popup.style.width = '260px';
popup.style.zIndex = '10000';
// Build inner HTML using safe concatenation
var html = '';
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>';
if (isEditor) {
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>';
}
popup.innerHTML = html;
document.body.appendChild(popup);
// Toggle display
btn.addEventListener('click', function () {
try {
if (popup.style.display === 'none' || popup.style.display === '') {
popup.style.display = 'block';
} else {
popup.style.display = 'none';
}
} catch (err) {
/* safe */
}
});
// Handle clicks inside popup (delegation)
popup.addEventListener('click', function (ev) {
var target = ev.target || ev.srcElement;
if (!target) return;
// Create Page button
if (target.id === 'createPageBtn') {
var pn = document.getElementById('newPageName');
if (!pn) return;
var raw = pn.value || '';
raw = trim(raw);
if (!raw) {
alert('Please enter a page name.');
return;
}
// Replace spaces with underscores for title
var title = raw.replace(/\s+/g, '_');
// Redirect to edit
var url = mw.util.getUrl(title) + '?action=edit&veaction=edit';
window.location.href = url;
return;
}
// Create Category button (editor only)
if (target.id === 'createCategoryBtn') {
var cn = document.getElementById('newCategoryName');
if (!cn) return;
var rawc = cn.value || '';
rawc = trim(rawc);
if (!rawc) {
alert('Please enter a category name.');
return;
}
// replace spaces with hyphens for category
var ctitle = 'Category:' + rawc.replace(/\s+/g, '-');
var curl = mw.util.getUrl(ctitle) + '?action=edit&veaction=edit';
window.location.href = curl;
return;
}
});
// Small helpers
function trim(s) {
return (s || '').replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
function indexOf(arr, val) {
if (!arr || !arr.length) return -1;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === val) return i;
}
return -1;
}
} catch (eInner) {
// Don't break other site JS
if (typeof console !== 'undefined' && console.error) {
console.error('CreateButton init error:', eInner);
}
}
}
} catch (e) {
if (typeof console !== 'undefined' && console.error) {
console.error('CreateButton outer error:', e);
}
}
})();
/* TeamDashboard - jQuery + ES5 Safe (MediaWiki 1.39)
Full client-side behavior: accordion, AJAX actions, comments, delete, search.
*/
(function ($) {
$(function () {
/** ---------- Small HTML escape ---------- **/
function escapeHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
/** ---------- Detect Special:TeamDashboard ---------- **/
var pageName = null;
try {
if (window.mw && mw.config && mw.config.get) {
pageName = mw.config.get('wgCanonicalSpecialPageName') || mw.config.get('wgPageName');
}
} catch (e) {}
if (!pageName) {
var path = (location.pathname || '').toLowerCase();
if (path.includes('/special:teamdashboard') || path.includes('title=special:teamdashboard')) {
pageName = 'TeamDashboard';
} else if ((document.title || '').toLowerCase().includes('team dashboard')) {
pageName = 'TeamDashboard';
}
}
if (!pageName || String(pageName).indexOf('TeamDashboard') === -1) return;
/** ---------- Accordion Logic ---------- **/
function initAccordionOnce() {
$('.accordion-toggle').each(function () {
var $el = $(this);
var targetSel = $el.attr('data-target');
if (!targetSel) return;
var $target = $(targetSel);
if (!$target.length) return;
if ($el.find('.pa-arrow').length === 0) {
$el.prepend('<span class="pa-arrow">▶ </span>');
}
try {
var saved = localStorage.getItem('pa:' + targetSel);
if (saved === 'open') {
$target.show();
$el.find('.pa-arrow').text('▼ ');
} else {
$target.hide();
$el.find('.pa-arrow').text('▶ ');
}
} catch (err) {}
if (!$el.data('pa-bound')) {
$el.on('click', function () {
var isOpen = $target.is(':visible');
$target.toggle(!isOpen);
$el.find('.pa-arrow').text(isOpen ? '▶ ' : '▼ ');
try {
localStorage.setItem('pa:' + targetSel, isOpen ? 'closed' : 'open');
} catch (e) {}
});
$el.data('pa-bound', true);
}
});
}
/** ---------- Get fresh CSRF token ---------- **/
function getFreshToken(callback) {
$.get(mw.util.wikiScript('api'), {
action: 'query',
meta: 'tokens',
type: 'csrf',
format: 'json'
}).done(function (data) {
if (data?.query?.tokens?.csrftoken) {
callback(data.query.tokens.csrftoken);
} else {
callback('');
}
}).fail(function () {
callback('');
});
}
/** ---------- AJAX Helper ---------- **/
function postAction(fd, onSuccess, onError) {
$.ajax({
url: location.href,
method: 'POST',
data: fd,
processData: false,
contentType: false,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
}).done(function (res) {
if (typeof onSuccess === 'function') onSuccess(res);
}).fail(function (xhr) {
if (typeof onError === 'function') onError(xhr);
});
}
/** ---------- 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');
var pageId = $btn.data('page-id');
$btn.prop('disabled', true);
// Get fresh CSRF token
getFreshToken(function (token) {
if (!token) {
alert('Session expired. Please reload.');
$btn.prop('disabled', false);
return;
}
var fd = new FormData();
fd.append('action', action);
fd.append('page_id', pageId);
fd.append('token', token);
if (action === 'forward') {
var $input = $btn.closest('td').find('input.comment-input');
if ($input.length) {
var v = $.trim($input.val());
if (v !== '') fd.append('comment', v);
}
}
postAction(fd, function () {
// optimistic UI
if (action === 'approve') {
$btn.text('Approved ✓').addClass('disabled').prop('disabled', true);
$btn.closest('td').prev().prev().text('approved');
$btn.closest('td').find('.comment-box').remove();
} else if (action === 'reject') {
$btn.text('Rejected ✗').addClass('disabled').prop('disabled', true);
$btn.closest('td').prev().prev().text('rejected');
} else if (action === 'forward') {
$btn.text('Forwarded ➜').addClass('disabled').prop('disabled', true);
}
$btn.prop('disabled', false);
}, function () {
$btn.prop('disabled', false);
alert('Action failed. Please try again.');
});
});
});
/** ---------- 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');
var $input = $wrap.find('input.comment-input');
var txt = $.trim($input.val());
if (txt === '') return;
var pageId = $btn.data('page-id');
$btn.prop('disabled', true);
getFreshToken(function (token) {
if (!token) {
alert('Session expired. Please reload the page.');
$btn.prop('disabled', false);
return;
}
var fd = new FormData();
fd.append('action', 'comment');
fd.append('page_id', pageId);
fd.append('token', token);
fd.append('comment', txt);
postAction(fd, function () {
var $td = $btn.closest('td');
var $list = $td.find('.comment-list');
if (!$list.length) {
var $cb = $('<div class="comment-box"><b>Comments</b><ul class="comment-list"></ul></div>');
$td.append($cb);
$list = $cb.find('.comment-list');
}
var li = $('<li/>').html('<b>You</b> <span class="date">(just now)</span><br/>' + escapeHtml(txt));
$list.prepend(li);
$input.val('');
$btn.prop('disabled', false);
}, function () {
$btn.prop('disabled', false);
alert('Could not add comment. Please try again.');
});
});
});
// Enter key submit
$(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');
var pageId = $btn.data('page-id');
$btn.prop('disabled', true);
getFreshToken(function (token) {
if (!token) {
alert('Session expired. Please reload.');
$btn.prop('disabled', false);
return;
}
var fd = new FormData();
fd.append('action', 'delete_comment');
fd.append('comment_id', commentId);
fd.append('page_id', pageId);
fd.append('token', token);
postAction(fd, function () {
$btn.closest('li').remove();
}, function () {
$btn.prop('disabled', false);
alert('Could not delete comment. Try again.');
});
});
});
/** ---------- Client-side Search ---------- **/
$(document).on('input', '.search-input', function () {
var q = $.trim($(this).val()).toLowerCase();
var $table = $(this).closest('div').nextAll('table.dashboard-table').first();
if (!$table.length) $table = $('.dashboard-table').first();
$table.find('tbody tr').each(function () {
var text = $(this).text().toLowerCase();
$(this).toggle(text.indexOf(q) !== -1);
});
});
/** ---------- Prevent accidental native submits ---------- **/
$('form').each(function () {
var $f = $(this);
try {
if ($f.hasClass('ajax-comment-form') || $f.find('input.comment-input').length) {
$f.attr('action', location.href);
}
} catch (e) {}
});
// init accordions
initAccordionOnce();
setTimeout(initAccordionOnce, 700);
});
})(jQuery);
