Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*
CONTENTS
1. Collapsible headings (taken from https://bahai9.com/index.php?title=MediaWiki:Common.js&action=edit )
2. Collapsible list (taken from https://bahai9.com/index.php?title=MediaWiki:Common.js&action=edit )
*/
// Collapsible headings
var a = $('<a href="javascript:void(0);">collapse</a>').click(function () {
var currentHeading = parseInt($(this).parent().parent()[0].nodeName.match(/\d$/));
var sameOrHigherHeading = 'h' + Array.from({length: 6}, function (x, i) {return i+1;}).slice(0, currentHeading).join(',h');
var method = this.textContent === 'collapse' ? 'hide' : 'show';
$(this).parent().parent().nextUntil(sameOrHigherHeading)[method]();
this.textContent = this.textContent === 'collapse' ? 'show' : 'collapse';
});
$('h1,h2,h3,h4,h5,h6').children('.mw-editsection').append(' [', a, ']');
// add collapsible list if an empty span is present indicating to do so
if ($('.enable_collapsibleList').length || $('.enable_collapsibleList_collapsed').length) {
$('ul,ol').each(function () {
$(this).addClass('collapsibleList');
var li = $(this).find('li:has(ul,ol)').addClass('collapsibleListOpen');
if (!li.find('span').length) {
li.prepend('<span style="user-select: none;"> </span>');
}
});
}
// User:Brettz9 added with some JSLint/XHTML/JSDoc clean-up, optimization/convenience changes, OL support, and beginning of work to allow pre-expansion of lists
/*
MEDIAWIKI LIST NOTES
Nested DL hierarchies do not work properly with Mediawiki (see bug at http://www.mediawiki.org/wiki/Thread:Project:Support_desk/How_to_create_nested_definition_lists%3F )
Resources:
1. http://www.mediawiki.org/wiki/Help:Formatting
2. http://en.wikipedia.org/wiki/Help:List
*/
/*
CollapsibleLists.js
An object allowing lists to dynamically expand and collapse
Original version created by Stephen Morley - http://code.stephenmorley.org/javascript/collapsible-lists/ -
and released under the terms of the CC0 1.0 Universal legal code:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
Ideas
1. Remember expanded states
2. Make DL collapsible via its DD
3. Support collapsing of DL component children (DD and DT)
Todo summary: (see "todo"'s below)
1. Optimize iteration algorithms
2. When #1 is completed, check top-most class of list (or its parent) for `doNotRecurse` and pre-expansion options
*/
// eslint-disable-next-line no-unused-vars -- Might expand
var CollapsibleLists;
(function () {
// Create the CollapsibleLists object
var collapsibleLists,
autoApplyWithNoGlobal = true; // Configure as to whether to auto-apply to lists on the page (without creating a global) or whether to allow manual control via a global
/**
* Opens or closes the list elements of the given type
* within the specified node.
* @private
* @static
* @param {Element} node The node containing the list elements
* @param {'ul'|'ol'} [listType] Type of list; defaults to "ul"
* @returns {int}
*/
function toggle (node, listType) {
listType = listType || 'ul,ol';
// Determine whether to open or close the lists
var index, li,
open = node.className.match(/(^| )collapsibleListClosed( |$)/),
// Loop over the list elements with the node
lists = node.querySelectorAll(listType),
listsLength = lists.length;
for (index = 0; index < listsLength; index++) {
// Find the ancestor list item of this list
li = lists[index];
while (li.nodeName.toLowerCase() !== 'li') {
li = li.parentNode;
}
// Style the list if it is within this node
if (li === node) {
lists[index].style.display = (open ? 'block' : 'none');
}
}
if (listsLength) {
// Remove the current class from the node
node.className = node.className.replace(
/(^| )collapsibleList(Open|Closed)( |$)/, ''
);
// If the node contains lists, set its class
if (listsLength > 0) {
node.className += ' collapsibleList' + (open ? 'Open' : 'Closed');
}
}
return listsLength;
}
/**
* @callback ClickHandler
* @private
* @static
* @param {Event} e The click event
* @returns {void}
*/
/**
* Returns a function that toggles the display status of any
* list elements within the specified node. The parameter is...
* @private
* @static
* @param {Element} node The node containing the list elements
* @returns {ClickHandler}
*/
function createClickListener (node) {
// Return the function
/**
* @type {ClickHandler}
*/
return function (e) {
// Ensure the event object is defined
e = e || window.event;
// Find the list item containing the target of the event
var li = e.target || e.srcElement;
while (li.nodeName.toLowerCase() !== 'li') {
li = li.parentNode;
}
// Toggle the state of the node if it was the target of the event
if (li === node) {
toggle(node);
}
};
}
/**
* @private
* @static
* @param {Event} e The event to prevent
* @returns {void}
*/
function preventDefault (e) {
e.preventDefault();
}
/**
* @private
* @static
* @returns {void}
*/
function preventDefaultIE () {
// eslint-disable-next-line no-restricted-globals -- IE
event.returnValue = false;
}
/**
* @param {boolean} leaveExpanded
* @private
* @static
* @returns {void}
*/
function applyLists (leaveExpanded) {
collapsibleLists.apply(false, leaveExpanded);
}
/**
* Makes sublists of a given list type collapsible.
* @private
* @static
* @param {Element} list The list element
* @param {'ul'|'ol'} [listType] The list type under which sublists should be made collapsible
* @returns {void}
*/
function applySubListsForListType (list, listType) {
listType = listType || 'ul,ol';
// Todo: This is unnecessarily redundant and thus expensive for deeply nested lists;
// should instead check direct children recursively
var subIndex,
subLists = list.getElementsByTagName(listType),
subListsLength = subLists.length;
for (subIndex = 0; subIndex < subListsLength; subIndex++) {
// Tempory fix to at least avoid multiple classes
if (!(/(^| )collapsibleList( |$)/).test(subLists[subIndex].className)) {
subLists[subIndex].className += ' collapsibleList';
}
}
}
collapsibleLists = {
/**
* Makes all lists with the class 'collapsibleList' collapsible.
* @param {boolean} [doNotRecurse] True if sub-lists should not be made collapsible
* @param {boolean} [leaveExpanded] True if list and its sublists should be left pre-expanded
* @returns {void}
*/
apply: function (doNotRecurse, leaveExpanded) {
this.applyForListType(doNotRecurse, leaveExpanded);
},
/**
* Makes lists of the given type with the class 'collapsibleList' collapsible.
* @param {boolean} [doNotRecurse] True if sub-lists should not be made collapsible
* @param {boolean} [leaveExpanded] True if list and its sublists should be left pre-expanded
* @param {'ul'|'ol'} [listType] Type of list; defaults to "ul"
*/
applyForListType: function (doNotRecurse, leaveExpanded, listType) {
listType = listType || 'ul,ol';
// Loop over the lists
var index, list,
// Todo: This is unnecessarily redundant and thus inefficient; should instead
// iterate over direct children
lists = document.querySelectorAll(listType),
listsLength = lists.length,
listPattern = /(^| )collapsibleList( |$)/;
for (index = 0; index < listsLength; index++) {
list = lists[index];
// Check whether this list should be made collapsible
if (listPattern.test(list.className) ||
listPattern.test(list.parentNode.className) // For convenience when used with Mediawiki simple syntax lists (which cannot specify classes on the list)
) {
// Make this list collapsible
this.applyTo(list, true, leaveExpanded);
// Check whether sub-lists should also be made collapsible
// Todo: When iteration algorithm is fixed, check class at top of list (or parent of list) to allow doNotRecurse specification
if (!doNotRecurse) {
// Add the collapsibleList class to the sub-lists
applySubListsForListType(list);
}
}
}
},
/**
* Makes the specified list collapsible.
* @param {Element} node The list element
* @param {boolean} [doNotRecurse] True if sub-lists should not be made collapsible
* @param {boolean} [leaveExpanded] True if list and its sublists should be left pre-expanded
*/
applyTo: function (node, doNotRecurse, leaveExpanded) {
// Loop over the list items within this node
var index,
lis = node.querySelectorAll('li'),
lisLength = lis.length;
for (index = 0; index < lisLength; index++) {
// Todo: When iteration algorithm is fixed, check class at top of list (or parent of list) to allow doNotRecurse specification
// Check whether this list item should be collapsible
if (!doNotRecurse || node === lis[index].parentNode) {
var attachNode = lis[index].querySelector('span');
if (!attachNode) {
continue;
}
// Prevent text from being selected unintentionally
if (attachNode.addEventListener) {
attachNode.addEventListener('mousedown', preventDefault, false);
} else {
attachNode.attachEvent('onselectstart', preventDefaultIE);
}
// Add the click listener
if (attachNode.addEventListener) {
attachNode.addEventListener('click', createClickListener(lis[index]), false);
} else {
attachNode.attachEvent('onclick', createClickListener(lis[index]));
}
// Close the lists within this list item
// Todo: When iteration algorithm is fixed, check class at top of list (or parent of list) to allow expansion via class
if (!leaveExpanded) {
toggle(lis[index]);
}
}
}
}
};
if (autoApplyWithNoGlobal) {
/*
if (window.addEventListener) {
window.addEventListener('DOMContentLoaded', applyLists, false);
}
else {
window.attachEvent('onload', applyLists);
}
*/
applyLists(!$('.enable_collapsibleList_collapsed').length);
} else {
CollapsibleLists = collapsibleLists;
}
}());