MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
m Add searchable floating contents panel |
m Restore floating expand collapse controls |
||
| (One intermediate revision by the same user not shown) | |||
| Line 14: | Line 14: | ||
}); | }); | ||
(function () { | |||
window.muhroGetFloatingTools = function () { | |||
var $tools = $('#muhro-floating-tools'); | |||
if (!$tools.length) { | |||
$tools = $('<div>') | |||
.attr('id', 'muhro-floating-tools') | |||
.addClass('muhro-floating-tools noprint'); | |||
$('body').append($tools); | |||
} | |||
return $tools; | |||
}; | |||
}()); | |||
(function () { | (function () { | ||
| Line 34: | Line 49: | ||
function findCollapsibles($root) { | function findCollapsibles($root) { | ||
return $root | return $root | ||
.find('.mw | .find('.mw-collapsible') | ||
.add($root.filter('.mw | .add($root.filter('.mw-collapsible')); | ||
} | } | ||
| Line 44: | Line 59: | ||
$expand.prop('disabled', $items.length === 0 || collapsedCount === 0); | $expand.prop('disabled', $items.length === 0 || collapsedCount === 0); | ||
$collapse.prop('disabled', $items.length === 0 || collapsedCount === $items.length); | $collapse.prop('disabled', $items.length === 0 || collapsedCount === $items.length); | ||
} | |||
function triggerFallback($element, collapse) { | |||
if ($element.hasClass('mw-collapsed') === collapse) { | |||
return; | |||
} | |||
$element.find('> .muhro-early-toggle, .muhro-early-toggle').first().trigger('click'); | |||
} | } | ||
| Line 51: | Line 74: | ||
var api = $element.data('mw-collapsible'); | var api = $element.data('mw-collapsible'); | ||
if ( | if ($element.hasClass('mw-collapsed') === collapse) { | ||
return; | return; | ||
} | } | ||
if (collapse) { | if (api) { | ||
api. | if (collapse) { | ||
api.collapse(); | |||
} else { | |||
api.expand(); | |||
} | |||
} else { | } else { | ||
triggerFallback($element, collapse); | |||
} | } | ||
}); | }); | ||
updateButtons($root, $expand, $collapse); | window.setTimeout(function () { | ||
updateButtons($root, $expand, $collapse); | |||
}, 0); | |||
} | } | ||
| Line 84: | Line 113: | ||
'aria-label': 'Collapsible content controls' | 'aria-label': 'Collapsible content controls' | ||
}) | }) | ||
.addClass('muhro-collapse-controls | .addClass('muhro-collapse-controls') | ||
.append($expand, $collapse); | .append($expand, $collapse); | ||
| Line 100: | Line 129: | ||
updateButtons($root, $expand, $collapse); | updateButtons($root, $expand, $collapse); | ||
window.muhroGetFloatingTools().prepend($controls); | |||
return true; | return true; | ||
} | } | ||
| Line 116: | Line 145: | ||
function tryAttach() { | function tryAttach() { | ||
attempts++; | attempts++; | ||
if (attachControls($root) || attempts >= | if (attachControls($root) || attempts >= 40) { | ||
return; | return; | ||
} | } | ||
| Line 218: | Line 247: | ||
$wrapper = $('<div>') | $wrapper = $('<div>') | ||
.attr('id', 'muhro-floating-toc') | .attr('id', 'muhro-floating-toc') | ||
.addClass('muhro-floating-toc | .addClass('muhro-floating-toc') | ||
.append($button, $panel); | .append($button, $panel); | ||
| Line 243: | Line 272: | ||
}); | }); | ||
window.muhroGetFloatingTools().append($wrapper); | |||
} | } | ||
mw.hook('wikipage.content').add(addFloatingToc); | mw.hook('wikipage.content').add(addFloatingToc); | ||
}()); | }()); | ||
Latest revision as of 14:49, 27 May 2026
/* Any JavaScript here will be loaded for all users on every page load. */
$('.copy-link').on('click', function() {
var link = $(this);
var copy_id = $(this).attr('id');
var text = $(this).text();
var clipboard = new ClipboardJS('#' + copy_id );
clipboard.on('success', function(e) {
link.text('Copied!');
setTimeout(function() {
link.text(''+text);
}, 2000);
});
});
(function () {
window.muhroGetFloatingTools = function () {
var $tools = $('#muhro-floating-tools');
if (!$tools.length) {
$tools = $('<div>')
.attr('id', 'muhro-floating-tools')
.addClass('muhro-floating-tools noprint');
$('body').append($tools);
}
return $tools;
};
}());
(function () {
function normalizeLegacyCollapsibles($root) {
var $legacy = $root.find('table.collapsible, div.collapsible, ul.collapsible, ol.collapsible')
.not('.mw-collapsible');
$legacy.each(function () {
var $element = $(this);
$element.addClass('mw-collapsible');
if ($element.hasClass('collapsed')) {
$element.addClass('mw-collapsed');
}
});
$legacy.makeCollapsible();
}
function findCollapsibles($root) {
return $root
.find('.mw-collapsible')
.add($root.filter('.mw-collapsible'));
}
function updateButtons($root, $expand, $collapse) {
var $items = findCollapsibles($root);
var collapsedCount = $items.filter('.mw-collapsed').length;
$expand.prop('disabled', $items.length === 0 || collapsedCount === 0);
$collapse.prop('disabled', $items.length === 0 || collapsedCount === $items.length);
}
function triggerFallback($element, collapse) {
if ($element.hasClass('mw-collapsed') === collapse) {
return;
}
$element.find('> .muhro-early-toggle, .muhro-early-toggle').first().trigger('click');
}
function setAll($root, collapse, $expand, $collapse) {
findCollapsibles($root).each(function () {
var $element = $(this);
var api = $element.data('mw-collapsible');
if ($element.hasClass('mw-collapsed') === collapse) {
return;
}
if (api) {
if (collapse) {
api.collapse();
} else {
api.expand();
}
} else {
triggerFallback($element, collapse);
}
});
window.setTimeout(function () {
updateButtons($root, $expand, $collapse);
}, 0);
}
function attachControls($root) {
if ($('#muhro-collapse-controls').length || !findCollapsibles($root).length) {
return false;
}
var $expand = $('<button>')
.attr('type', 'button')
.addClass('muhro-collapse-button')
.text('Expand all');
var $collapse = $('<button>')
.attr('type', 'button')
.addClass('muhro-collapse-button')
.text('Collapse all');
var $controls = $('<div>')
.attr({
id: 'muhro-collapse-controls',
role: 'group',
'aria-label': 'Collapsible content controls'
})
.addClass('muhro-collapse-controls')
.append($expand, $collapse);
$expand.on('click', function () {
setAll($root, false, $expand, $collapse);
});
$collapse.on('click', function () {
setAll($root, true, $expand, $collapse);
});
$root.on('click keydown', '.mw-collapsible-toggle', function () {
window.setTimeout(function () {
updateButtons($root, $expand, $collapse);
}, 0);
});
updateButtons($root, $expand, $collapse);
window.muhroGetFloatingTools().prepend($controls);
return true;
}
function addCollapsibleControls($content) {
var $root = $content.find('.mw-parser-output').first();
var attempts = 0;
if (!$root.length) {
$root = $content;
}
normalizeLegacyCollapsibles($root);
function tryAttach() {
attempts++;
if (attachControls($root) || attempts >= 40) {
return;
}
window.setTimeout(tryAttach, 250);
}
tryAttach();
}
mw.loader.using('jquery.makeCollapsible').then(function () {
mw.hook('wikipage.content').add(addCollapsibleControls);
});
}());
(function () {
function filterToc($panel, query) {
var normalized = query.trim().toLowerCase();
$panel.find('li').removeClass('muhro-toc-match muhro-toc-hidden muhro-toc-ancestor');
if (!normalized) {
return;
}
$panel.find('li').each(function () {
var $item = $(this);
var text = $item.children('a').first().text().toLowerCase();
if (text.indexOf(normalized) !== -1) {
$item.addClass('muhro-toc-match');
$item.parents('li').addClass('muhro-toc-ancestor');
}
});
$panel.find('li').each(function () {
var $item = $(this);
if (!$item.hasClass('muhro-toc-match') && !$item.hasClass('muhro-toc-ancestor')) {
$item.addClass('muhro-toc-hidden');
}
});
}
function addFloatingToc($content) {
var $toc = $content.find('#toc').first();
var $tocList;
var $button;
var $panel;
var $header;
var $filter;
var $body;
var $wrapper;
if ($('#muhro-floating-toc').length || !$toc.length) {
return;
}
$tocList = $toc.find('> ul, .toc > ul').first().clone(false);
if (!$tocList.length) {
$tocList = $toc.find('ul').first().clone(false);
}
if (!$tocList.length) {
return;
}
$tocList.find('[id]').removeAttr('id');
$tocList.find('.tocnumber').attr('aria-hidden', 'true');
$button = $('<button>')
.attr({
type: 'button',
'aria-expanded': 'false',
'aria-controls': 'muhro-floating-toc-panel'
})
.addClass('muhro-floating-toc-button')
.text('Contents');
$filter = $('<input>')
.attr({
type: 'search',
placeholder: 'Filter contents',
'aria-label': 'Filter contents'
})
.addClass('muhro-floating-toc-filter');
$header = $('<div>')
.addClass('muhro-floating-toc-header')
.append($filter);
$body = $('<div>')
.addClass('muhro-floating-toc-body')
.append($tocList);
$panel = $('<nav>')
.attr({
id: 'muhro-floating-toc-panel',
'aria-label': 'Page contents'
})
.addClass('muhro-floating-toc-panel')
.append($header, $body);
$wrapper = $('<div>')
.attr('id', 'muhro-floating-toc')
.addClass('muhro-floating-toc')
.append($button, $panel);
$button.on('click', function () {
var open = !$wrapper.hasClass('is-open');
$wrapper.toggleClass('is-open', open);
$button.attr('aria-expanded', open ? 'true' : 'false');
if (open) {
window.setTimeout(function () {
$filter.trigger('focus');
}, 0);
}
});
$filter.on('input', function () {
filterToc($panel, $filter.val());
});
$panel.on('click', 'a', function () {
if (window.matchMedia('(max-width: 720px)').matches) {
$wrapper.removeClass('is-open');
$button.attr('aria-expanded', 'false');
}
});
window.muhroGetFloatingTools().append($wrapper);
}
mw.hook('wikipage.content').add(addFloatingToc);
}());