MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
No edit summary Tag: Manual revert |
No edit summary |
||
Line 1: | Line 1: | ||
mw. | /** | ||
$(function () { | * Collapsible Sidebar (Debug Build) for MW 1.44 (Vector + Vector 2022) | ||
* - Writes verbose logs to the console | |||
* - Inserts a real <span> arrow (▶), so you see it even if :before fails | |||
* - No jquery.cookie, no extra modules | |||
* | |||
* Toggle logging at runtime with: window.MWSidebarDebug = true/false | |||
*/ | |||
(function () { | |||
// Turn on debug by default; you can turn off in the console if too chatty. | |||
window.MWSidebarDebug = true; | |||
function log() { | |||
if (window.MWSidebarDebug && typeof console !== 'undefined') { | |||
console.log.apply(console, ['[SidebarCollapsible]'].concat([].slice.call(arguments))); | |||
} | |||
} | |||
function warn() { | |||
if (typeof console !== 'undefined') { | |||
console.warn.apply(console, ['[SidebarCollapsible]'].concat([].slice.call(arguments))); | |||
} | |||
} | |||
var skin = mw.config.get('skin'); | |||
log('Init start. Detected skin =', skin); | |||
function findTopList($panel) { | |||
// Works for Vector/Vector-2022 portlets and (fallback) legacy .portal markup | |||
return $panel.find('> .vector-menu-content > .vector-menu-content-list, > .body > ul').first(); | |||
} | |||
function initOnce($root) { | |||
// Find all sidebar portlets that look like menus | |||
var $panels = $('#mw-panel .vector-menu-portal, .vector-menu-portal', $root); | |||
if (!$panels.length) { | |||
warn('No .vector-menu-portal found. Are you using Vector/Vector-2022?'); | |||
} else { | |||
log('Found', $panels.length, 'portal(s).'); | |||
} | |||
$panels.each(function (idx, el) { | |||
var $panel = $(el); | |||
var id = $panel.attr('id') || ('panel#' + idx); | |||
var $list = findTopList($panel); | |||
if (!$list.length) { | |||
warn('Panel has no UL list:', id, $panel.get(0)); | |||
return; | |||
} | |||
var $items = $list.children('li'); | |||
log('Panel', id, ':', $items.length, 'top-level <li> item(s).'); | |||
$items.each(function (i, li) { | |||
var $li = $(li); | |||
var $sub = $li.children('ul'); | |||
if (!$sub.length) { | |||
// Not a collapsible candidate | |||
return; | |||
} | |||
// Mark as collapsible and hide sub-list (if not already) | |||
$li.addClass('collapsible-header'); | |||
if (!$li.children('.mw-collapsible-arrow').length) { | |||
// Insert a real arrow character so it’s guaranteed visible | |||
$li.prepend($('<span class="mw-collapsible-arrow" aria-hidden="true">▶</span>')); | |||
} | |||
$sub.hide(); | |||
// Log header text for reference | |||
var headerText = ($li.find('> a').first().text() || $li.clone().children().remove().end().text() || '') | |||
.trim() | |||
.replace(/\s+/g, ' '); | |||
log('Registered collapsible item', i, 'in', id, 'header=', headerText); | |||
// Click to toggle (but let actual links work) | |||
$li.off('.mwCollapsibleSidebar') // avoid duplicate binding | |||
.on('click.mwCollapsibleSidebar', function (e) { | |||
if ($(e.target).closest('a').length) { | |||
// Click on a link inside; do not toggle | |||
log('Link click passthrough for header:', headerText); | |||
return; | |||
} | } | ||
e.preventDefault(); | |||
var willOpen = !$li.hasClass('open'); | |||
$li.toggleClass('open'); | |||
$sub.stop(true, true).slideToggle(200); | |||
log('Toggled', (willOpen ? 'open' : 'closed') + ':', headerText); | |||
}); | |||
}); | |||
}); | |||
} | |||
// Run on DOM ready and on content re-renders | |||
mw.loader.using('mediawiki.util').then(function () { | |||
$(function () { | |||
console.group && console.group('[SidebarCollapsible] bootstrap'); | |||
initOnce($(document)); | |||
console.groupEnd && console.groupEnd(); | |||
}); | |||
mw.hook('wikipage.content').add(function ($c) { | |||
log('wikipage.content hook fired (re-init on dynamic content).'); | |||
initOnce($c); | |||
}); | }); | ||
}); | }); | ||
})(); |
Revision as of 20:28, 25 August 2025
/** * Collapsible Sidebar (Debug Build) for MW 1.44 (Vector + Vector 2022) * - Writes verbose logs to the console * - Inserts a real <span> arrow (▶), so you see it even if :before fails * - No jquery.cookie, no extra modules * * Toggle logging at runtime with: window.MWSidebarDebug = true/false */ (function () { // Turn on debug by default; you can turn off in the console if too chatty. window.MWSidebarDebug = true; function log() { if (window.MWSidebarDebug && typeof console !== 'undefined') { console.log.apply(console, ['[SidebarCollapsible]'].concat([].slice.call(arguments))); } } function warn() { if (typeof console !== 'undefined') { console.warn.apply(console, ['[SidebarCollapsible]'].concat([].slice.call(arguments))); } } var skin = mw.config.get('skin'); log('Init start. Detected skin =', skin); function findTopList($panel) { // Works for Vector/Vector-2022 portlets and (fallback) legacy .portal markup return $panel.find('> .vector-menu-content > .vector-menu-content-list, > .body > ul').first(); } function initOnce($root) { // Find all sidebar portlets that look like menus var $panels = $('#mw-panel .vector-menu-portal, .vector-menu-portal', $root); if (!$panels.length) { warn('No .vector-menu-portal found. Are you using Vector/Vector-2022?'); } else { log('Found', $panels.length, 'portal(s).'); } $panels.each(function (idx, el) { var $panel = $(el); var id = $panel.attr('id') || ('panel#' + idx); var $list = findTopList($panel); if (!$list.length) { warn('Panel has no UL list:', id, $panel.get(0)); return; } var $items = $list.children('li'); log('Panel', id, ':', $items.length, 'top-level <li> item(s).'); $items.each(function (i, li) { var $li = $(li); var $sub = $li.children('ul'); if (!$sub.length) { // Not a collapsible candidate return; } // Mark as collapsible and hide sub-list (if not already) $li.addClass('collapsible-header'); if (!$li.children('.mw-collapsible-arrow').length) { // Insert a real arrow character so it’s guaranteed visible $li.prepend($('<span class="mw-collapsible-arrow" aria-hidden="true">▶</span>')); } $sub.hide(); // Log header text for reference var headerText = ($li.find('> a').first().text() || $li.clone().children().remove().end().text() || '') .trim() .replace(/\s+/g, ' '); log('Registered collapsible item', i, 'in', id, 'header=', headerText); // Click to toggle (but let actual links work) $li.off('.mwCollapsibleSidebar') // avoid duplicate binding .on('click.mwCollapsibleSidebar', function (e) { if ($(e.target).closest('a').length) { // Click on a link inside; do not toggle log('Link click passthrough for header:', headerText); return; } e.preventDefault(); var willOpen = !$li.hasClass('open'); $li.toggleClass('open'); $sub.stop(true, true).slideToggle(200); log('Toggled', (willOpen ? 'open' : 'closed') + ':', headerText); }); }); }); } // Run on DOM ready and on content re-renders mw.loader.using('mediawiki.util').then(function () { $(function () { console.group && console.group('[SidebarCollapsible] bootstrap'); initOnce($(document)); console.groupEnd && console.groupEnd(); }); mw.hook('wikipage.content').add(function ($c) { log('wikipage.content hook fired (re-init on dynamic content).'); initOnce($c); }); }); })();