MediaWiki:Gadget-defaultVisibilityToggles.js: Difference between revisions

From Linguifex
Jump to navigation Jump to search
No edit summary
Tag: Reverted
No edit summary
Tag: Manual revert
 
Line 1: Line 1:
/* jshint undef: true, esversion: 5 */
/* jshint undef: true */
/* globals $, jQuery, mw, window, getComputedStyle */
/* globals $, jQuery, mw, window, getComputedStyle */


(function defaultVisibilityTogglesIIFE() {
"use strict";
if (window.noDefaultVisibilityToggles) return;
/* == NavBars == */
var NavigationBarHide = "hide ▲";
var NavigationBarShow = "show ▼";
var nbsp = "\u00a0";
// Check if an element has been activated with a toggle.
// For convenience, this has the side effect of marking the element as having
// a toggle, if it is not already marked.
// Allows the functions to avoid toggleifying elements more than once, which
// can lead to multiple "show" buttons, for instance.
// The argument must be an Element, not a jQuery object.
function checkAndSetToggleified(element) {
if (element.isToggleified) {
return true;
}
element.isToggleified = true;
}
function getToggleCategory(element, defaultCategory) {
if ($(element).find("table").first().is(".translations"))
return "translations";
var heading = element;
while ((heading = heading.previousElementSibling)) {
// tagName is always uppercase:
// https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName
var num = heading.tagName.match(/H(\d)/);
if (num)
num = Number(num[1]);
else
continue;
if (4 <= num && num <= 6) {
if (heading.getElementsByTagName("span")[1])
heading = heading.getElementsByTagName("span")[0];
var text = jQuery(heading).text()
.toLowerCase()
// jQuery's .text() is inconsistent about whitespace:
.replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ")
// remove numbers added by the "Auto-number headings" pref:
.replace(/^[1-9][0-9.]+ ?/, "");
// Toggle category must be convertible to a valid CSS identifier so
// that it can be used in an id selector in jQuery in
// ToggleCategory.prototype.newSidebarToggle
// in [[MediaWiki:Gadget-VisibilityToggles.js]].
// Spaces must later be converted to hyphens or underscores.
// Reference: https://drafts.csswg.org/selectors-4/#id-selectors
if (/^[a-zA-Z0-9\s_-]+$/.test(text))
return text;
else
break;
} else if (num)
break;
}
return defaultCategory;
}
function createNavToggle(navFrame) {
if (checkAndSetToggleified(navFrame)) {
return;
}
var navHead, navContent;
for (var i = 0, children = navFrame.childNodes; i < children.length; ++i) {
var child = children[i];
if (child.nodeName === "DIV") {
var classList = child.classList;
if (classList.contains("NavHead"))
navHead = child;
if (classList.contains("NavContent"))
navContent = child;
}
}
if (!(navHead && navContent))
return;
// Step 1, don't react when a subitem is clicked.
$(navHead).find("a").on("click", function (e) {
e.stopPropagation();
e.stopImmediatePropagation();
});
// Step 2, toggle visibility when bar is clicked.
// NOTE This function was chosen due to some funny behaviour in Safari.
var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
$("<span>").addClass("NavToggle").attr("data-nosnippet", "")
.append($navToggle)
.prependTo(navHead);
navHead.style.cursor = "pointer";
var toggleCategory = $(navFrame).data("toggle-category")
|| getToggleCategory(navFrame, "other boxes");
navHead.onclick = window.VisibilityToggles.register(toggleCategory,
function show() {
$navToggle.text(NavigationBarHide);
if (navContent)
navContent.style.display = "block";
},
function hide() {
$navToggle.text(NavigationBarShow);
if (navContent)
navContent.style.display = "none";
});
}
function createNavToggleForInflectionTable(it) {
if (checkAndSetToggleified(it)) {
return;
}
// The table caption is the clickable element
var itCaption = $(it).find("caption").get(0);
// Step 1, don't react when a subitem is clicked.
$(itCaption).find("a").on("click", function (e) {
e.stopPropagation();
e.stopImmediatePropagation();
});
// Step 2, toggle visibility when bar is clicked.
// NOTE This function was chosen due to some funny behaviour in Safari.
var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
$("<span>").addClass("NavToggle").attr("data-nosnippet", "")
.append($navToggle)
.prependTo(itCaption);
itCaption.style.cursor = "pointer";
var toggleCategory = $(it).data("toggle-category")
|| getToggleCategory(it, "other boxes");
itCaption.onclick = window.VisibilityToggles.register(toggleCategory,
function show() {
$navToggle.text(NavigationBarHide);
if (it) {
it.classList.remove("inflection-table-collapsed");
}
},
function hide() {
$navToggle.text(NavigationBarShow);
if (it) {
it.classList.add("inflection-table-collapsed");
}
});
// Check to see if we are on a browser that is known to support
// visibility: collapse, which permits inflection table headings to wrap.
// WebKit needs to be special-cased, as technically it does support
// visibility: collapse, but it just implements it as a synonym for
// visibility: hidden, which is useless. (as of November 2024)
// Yes, I know User-Agent sniffing is so 2004... but WebKit is the new IE
if (
CSS && CSS.supports && CSS.supports("visibility:collapse") &&
// exclude WebKit/Safari, excepting Blink engines which have a frozen WebKit version number
(navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1)
) {
it.classList.remove("no-vc");
} else {
// Strange behaviour occurs when you set the table caption to nowrap
// The [show/hide] toggle crashes into the caption text
// This spacer element prevents that
$("<span>").addClass("no-vc-spacer").appendTo(itCaption);
}
}
/* ==Hidden Quotes== */
function setupHiddenQuotes(li) {
if (checkAndSetToggleified(li))
return;
let HQToggleButton, liComp, dl;


(function () {
function show() {
    "use strict";
HQToggleButton.text("quotations ▲");
$(li).children("ul").show();
}
function hide() {
HQToggleButton.text("quotations ▼");
$(li).children("ul").hide();
}
for (const liComp of li.childNodes) {
// Look at each component of the definition.
if (liComp.tagName === "DL" && !dl)
dl = liComp;


    if (window.noDefaultVisibilityToggles) return;
// If we find a ul or dl, we have quotes or example sentences, and thus need a button.
 
if (liComp.tagName === "UL") {
    var NavigationBarHide = "hide ▲";
$(li).children("ul").addClass("wikt-quote-container");
    var NavigationBarShow = "show ▼";
HQToggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
 
$(dl || liComp).before($("<span>").addClass("HQToggle").attr("data-nosnippet", "").append(HQToggleButton).css("margin-left", "5px"));
    var nbsp = "\u00a0";
HQToggleButton.on("click", window.VisibilityToggles.register("quotations", show, hide));
 
break;
    function checkAndSetToggleified(element) {
}
        if (element.isToggleified) {
}
            return true;
}
        }
        element.isToggleified = true;
/* == View Switching == */
    }
 
function viewSwitching(rootElement) {
    function getToggleCategory(element, defaultCategory) {
if (checkAndSetToggleified(rootElement)) {
        if ($(element).find("table").first().is(".translations"))
return;
            return "translations";
}
 
        var heading = element;
var $rootElement = $(rootElement);
        while ((heading = heading.previousElementSibling)) {
var showButtonText = $rootElement.data("vs-showtext") || "more ▼";
            var num = heading.tagName.match(/H(\d)/);
var hideButtonText = $rootElement.data("vs-hidetext") || "less ▲";
            if (num)
                num = Number(num[1]);
var toSkip = $rootElement.find(".vsSwitcher").find("*");
            else
var elemsToHide = $rootElement.find(".vsHide").not(toSkip);
                continue;
var elemsToShow = $rootElement.find(".vsShow").not(toSkip);
            if (4 <= num && num <= 6) {
                if (heading.getElementsByTagName("span")[1])
// Find the element to place the toggle button in.
                    heading = heading.getElementsByTagName("span")[0];
var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first();
                var text = jQuery(heading).text()
                    .toLowerCase()
// The toggleElement becomes clickable in its entirety, but
                    .replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ")
// we need to prevent this if a contained link is clicked instead.
                    .replace(/^[1-9][0-9.]+ ?/, "");
toggleElement.find("a").on("click", function (e) {
                if (/^[a-zA-Z0-9\s_-]+$/.test(text))
e.stopPropagation();
                    return text;
e.stopImmediatePropagation();
                else
});
                    break;
            } else if (num)
// Add the toggle button.
                break;
var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
        }
 
$("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement);
        return defaultCategory;
    }
// Determine the visibility toggle category (for the links in the bar on the left).
 
var toggleCategory = $rootElement.data("toggle-category");
    function createNavToggle(navFrame) {
if (!toggleCategory) {
        if (checkAndSetToggleified(navFrame)) {
var classNames = $rootElement.attr("class").split(/\s+/);
            return;
        }
for (var i = 0; i < classNames.length; ++i) {
 
var className = classNames[i].split("-");
        var navHead, navContent;
        var children = navFrame.childNodes;
if (className[0] == "vsToggleCategory") {
        for (var i = 0; i < children.length; ++i) {
toggleCategory = className[1];
            var child = children[i];
}
            if (child.nodeName === "DIV") {
}
                var classList = child.classList;
}
                if (classList.contains("NavHead"))
                    navHead = child;
if (!toggleCategory)
                if (classList.contains("NavContent"))
toggleCategory = "others";
                    navContent = child;
            }
// Register the visibility toggle.
        }
toggleElement.css("cursor", "pointer");
        if (!(navHead && navContent))
toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
            return;
function show() {
 
toggleButton.text(hideButtonText);
        $(navHead).find("a").on("click", function (e) {
elemsToShow.hide();
            e.stopPropagation();
elemsToHide.show();
            e.stopImmediatePropagation();
},
        });
function hide() {
 
toggleButton.text(showButtonText);
        var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
elemsToShow.show();
 
elemsToHide.hide();
        $("<span>").addClass("NavToggle").attr("data-nosnippet", "")
}));
            .append($navToggle)
}
            .prependTo(navHead);
 
/* ==List switching== */
        navHead.style.cursor = "pointer";
function enableListSwitchGeneric(rootElement) {
        var toggleCategory = $(navFrame).data("toggle-category") || getToggleCategory(navFrame, "other boxes");
if (checkAndSetToggleified(rootElement)) {
        navHead.onclick = window.VisibilityToggles.register(toggleCategory,
return;
            function show() {
}
                $navToggle.text(NavigationBarHide);
                if (navContent)
var $rootElement = $(rootElement);
                    navContent.style.display = "block";
            },
// Create a toggle button.
            function hide() {
var $toggleElement = $("<div>").addClass("list-switcher-element");
                $navToggle.text(NavigationBarShow);
var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", "");
                if (navContent)
var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
                    navContent.style.display = "none";
            });
// Add the toggle button to the DOM tree.
    }
$navToggle.append($toggleButton).prependTo($toggleElement);
 
$toggleElement.insertAfter($rootElement);
    function createNavToggleForInflectionTable(it) {
$toggleElement.show();
        if (checkAndSetToggleified(it)) {
            return;
// Determine the visibility toggle category (for the links in the bar on the
        }
// left). It will either be the value of the "data-toggle-category"
 
// attribute or will be based on the text of the closest preceding
        var itCaption = $(it).find("caption").get(0);
// fourth-to-sixth-level header.
 
var toggleCategory = $rootElement.data("toggle-category")
        $(itCaption).find("a").on("click", function (e) {
|| getToggleCategory($rootElement[0], "other lists");
            e.stopPropagation();
            e.stopImmediatePropagation();
// Determine the text for the $toggleButton.
        });
var showButtonText = "show more ▼";
 
var hideButtonText = "show less ▲";
        var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
var numItems;
 
// special handling for [[Module:collapsible category tree]]
        $("<span>").addClass("NavToggle").attr("data-nosnippet", "")
var $categoryTreeTag = $rootElement.children(".CategoryTreeTag");
            .append($navToggle)
if ($categoryTreeTag) {
            .prependTo(itCaption);
if ($categoryTreeTag.attr("data-pages-left-over") !== "0") {
 
// some category members are omitted from the list (MediaWiki limitation)
        itCaption.style.cursor = "pointer";
// just use basic "show more/less" in this case for now, this is a big change
        var toggleCategory = $(it).data("toggle-category") || getToggleCategory(it, "other boxes");
//showButtonText = "show first 200 of " + $categoryTreeTag.attr("data-pages-in-cat") + " ▼";
        itCaption.onclick = window.VisibilityToggles.register(toggleCategory,
//hideButtonText = "show fewer ▲";
            function show() {
} else {
                $navToggle.text(NavigationBarHide);
// all category members are included in the list
                if (it) {
numItems = $categoryTreeTag.attr("data-pages-in-cat");
                    it.classList.remove("inflection-table-collapsed");
}
                }
} else {
            },
// standard list-switcher using <li> elements
            function hide() {
numItems = $rootElement.find("li").length;
                $navToggle.text(NavigationBarShow);
}
                if (it) {
if (numItems) {
                    it.classList.add("inflection-table-collapsed");
showButtonText = "show all " + numItems + " ▼";
                }
hideButtonText = "show fewer ▲";
            });
}
 
        if (
// Register the visibility toggle.
            CSS && CSS.supports && CSS.supports("visibility:collapse") &&
$toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
            (navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1)
function show() {
        ) {
$toggleButton.text(hideButtonText);
            it.classList.remove("no-vc");
if (rootElement) {
        } else {
rootElement.classList.remove("list-switcher-collapsed");
            $("<span>").addClass("no-vc-spacer").appendTo(itCaption);
}
        }
},
    }
function hide() {
 
$toggleButton.text(showButtonText);
    function setupHiddenQuotes(li) {
if (rootElement) {
        if (checkAndSetToggleified(li))
rootElement.classList.add("list-switcher-collapsed");
            return;
}
 
}));
        var HQToggleButton, dl;
 
// Register a resize observer to see if we need to keep the
        function show() {
// show/hide toggle visible
            HQToggleButton.text("quotations ▲");
var termList = rootElement.querySelector(':scope > .term-list');
            $(li).children("ul").show();
if (termList && window.ResizeObserver) {
        }
var resizeObserver = new ResizeObserver(function(entries) {
        function hide() {
if (entries[0] && entries[0].contentBoxSize[0]) {
            HQToggleButton.text("quotations ▼");
// Work out what the max-height would be, in pixels
            $(li).children("ul").hide();
// As a hack, this value is stored in the CSS `bottom`
        }
// property, as `max-height` is only in place when
 
// the list is collapsed, but we need to do this check
        var liComp;
// even when the list is not collapsed
        for (var i = 0; i < li.childNodes.length; i++) {
var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom);
            liComp = li.childNodes[i];
            if (liComp.tagName === "DL" && !dl)
// If box height is less than its max height + 20 px, suppress
                dl = liComp;
// collapsibility. The 20 px buffer prevents the situation where
            if (liComp.tagName === "UL") {
// clicking "show more" expands the box by just a few pixels
                $(li).children("ul").addClass("wikt-quote-container");
if (entries[0].contentBoxSize[0].blockSize <= maxHeightPx + 20) {
                HQToggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
$toggleElement.hide();
                $(dl || liComp).before($("<span>").addClass("HQToggle").attr("data-nosnippet", "").append(HQToggleButton).css("margin-left", "5px"));
if (rootElement.classList.contains("list-switcher-collapsed")) {
                HQToggleButton.on("click", window.VisibilityToggles.register("quotations", show, hide));
rootElement.classList.remove("list-switcher-collapsed");
                break;
rootElement.classList.add("list-switcher-collapsibility-suppressed");
            }
}
        }
} else {
    }
$toggleElement.show();
 
if (rootElement.classList.contains("list-switcher-collapsibility-suppressed")) {
    function viewSwitching(rootElement) {
rootElement.classList.remove("list-switcher-collapsibility-suppressed");
        if (checkAndSetToggleified(rootElement)) {
rootElement.classList.add("list-switcher-collapsed");
            return;
}
        }
}
 
}
        var $rootElement = $(rootElement);
});
        var showButtonText = $rootElement.data("vs-showtext") || "more ▼";
        var hideButtonText = $rootElement.data("vs-hidetext") || "less ▲";
resizeObserver.observe(termList);
 
}
        var toSkip = $rootElement.find(".vsSwitcher").find("*");
}
        var elemsToHide = $rootElement.find(".vsHide").not(toSkip);
        var elemsToShow = $rootElement.find(".vsShow").not(toSkip);
// based on [[User:Erutuon/scripts/semhide.js]], [[User:Jberkel/semhide.js]],
 
// [[User:Ungoliant_MMDCCLXIV/synshide.js]]
        var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first();
function setupNyms(index, dlTag) {
 
// [[Wiktionary:Semantic relations]]
        toggleElement.find("a").on("click", function (e) {
var relationClasses = [ "synonym", "antonym", "hypernym", "hyponym", "meronym",
            e.stopPropagation();
"holonym", "troponym", "comeronym", "coordinate-term",
            e.stopImmediatePropagation();
"near-synonym", "imperfective", "perfective", "alternative-form" ];
        });
 
var relations = $(dlTag).find("dd > .nyms").get().filter(
        var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
function(element) {
 
return Array.prototype.some.call(element.classList, function (className) {
        $("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement);
if (relationClasses.indexOf(className) !== -1) {
 
element.dataset.relationClass = className;
        var toggleCategory = $rootElement.data("toggle-category");
return true;
        if (!toggleCategory) {
}
            var classNames = $rootElement.attr("class").split(/\s+/);
});
 
});
            for (var i = 0; i < classNames.length; ++i) {
                var className = classNames[i].split("-");
function setupToggle(elements, category, visibleByDefault) {
 
if (elements.length === 0) return null;
                if (className[0] == "vsToggleCategory") {
var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
                    toggleCategory = className[1];
var text = elements.map(function (e) {
                }
var linkCount = e.querySelectorAll("span[lang]").length;
            }
return e.dataset.relationClass.replace("-", " ") +
        }
(linkCount > 1 ? "s" : "");
 
}).join(", ");
        if (!toggleCategory)
            toggleCategory = "others";
function show() {
 
toggler.text(text + nbsp + "▲");
        toggleElement.css("cursor", "pointer");
$(dlTag).show();
        toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
$(elements).show();
            function show() {
}
                toggleButton.text(hideButtonText);
function hide() {
                elemsToShow.hide();
toggler.text(text + nbsp + "▼");
                elemsToHide.show();
if ($(dlTag).children().length === elements.length) {
            },
$(dlTag).hide();
            function hide() {
} else {
                toggleButton.text(showButtonText);
$(elements).hide();
                elemsToShow.show();
}
                elemsToHide.hide();
}
            }));
    }
$(dlTag).before($("<span>")
 
.addClass("nyms-toggle")
    function enableListSwitchGeneric(rootElement) {
.attr("data-nosnippet", "")
        if (checkAndSetToggleified(rootElement)) {
.append(toggler)
            return;
.css("margin-left", "5px"));
        }
 
toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
        var $rootElement = $(rootElement);
}
 
        var $toggleElement = $("<div>").addClass("list-switcher-element");
var synonyms = relations.filter(function (e) {
        var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", "");
return ["synonym", "antonym", "near-synonym", "coordinate-term", "alternative-form"].indexOf(e.dataset.relationClass) !== -1;
        var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
});
 
var other = relations.filter(function (e) { return synonyms.indexOf(e) === -1; });
        $navToggle.append($toggleButton).prependTo($toggleElement);
        $toggleElement.insertAfter($rootElement);
setupToggle(synonyms, "synonyms", true /* show by default  */);
        $toggleElement.show();
setupToggle(other, "semantic relations");
 
}
        var toggleCategory = $rootElement.data("toggle-category") || getToggleCategory($rootElement[0], "other lists");
 
        var showButtonText = "show more ▼";
function setupUsageExampleCollapses(index, dlTag) {
        var hideButtonText = "show less ▲";
var usexTags = $(dlTag).find("dd > .h-usage-example").get();
        var numItems;
        var $categoryTreeTag = $rootElement.children(".CategoryTreeTag");
function setupToggle(elements, category, visibleByDefault) {
        if ($categoryTreeTag) {
if (elements.length === 0) return null;
            if ($categoryTreeTag.attr("data-pages-left-over") !== "0") {
var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
            } else {
                numItems = $categoryTreeTag.attr("data-pages-in-cat");
function show() {
            }
toggler.text(category + nbsp + "");
        } else {
$(dlTag).show();
            numItems = $rootElement.find("li").length;
$(elements).show();
        }
}
        if (numItems) {
function hide() {
            showButtonText = "show all " + numItems + " ";
toggler.text(category + nbsp + "▼");
            hideButtonText = "show fewer ▲";
if ($(dlTag).children().length === elements.length) {
        }
$(dlTag).hide();
 
} else {
        $toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
$(elements).hide();
            function show() {
}
                $toggleButton.text(hideButtonText);
}
                if (rootElement) {
                    rootElement.classList.remove("list-switcher-collapsed");
$(dlTag).before($("<span>")
                }
.addClass("nyms-toggle")
            },
.append(toggler)
            function hide() {
.css("margin-left", "5px"));
                $toggleButton.text(showButtonText);
                if (rootElement) {
toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
                    rootElement.classList.add("list-switcher-collapsed");
}
                }
            }));
var collocations = usexTags.filter(function (e) {
 
return $(e).hasClass("collocation");
        var termList = rootElement.querySelector(':scope > .term-list');
});
        if (termList && window.ResizeObserver) {
var usexes = usexTags.filter(function (e) { return collocations.indexOf(e) === -1; });
            var resizeObserver = new ResizeObserver(function (entries) {
                if (entries[0] && entries[0].contentBoxSize[0]) {
setupToggle(usexes, "usage examples", true /* show by default */);
                    var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom);
setupToggle(collocations, "collocations", true /* show by default */);
 
}
                    if (entries[0].contentBoxSize[0].blockSize <= maxHeightPx + 20) {
                        $toggleElement.hide();
                        if (rootElement.classList.contains("list-switcher-collapsed")) {
window.createNavToggle = createNavToggle;
                            rootElement.classList.remove("list-switcher-collapsed");
window.setupHiddenQuotes = setupHiddenQuotes;
                            rootElement.classList.add("list-switcher-collapsibility-suppressed");
window.viewSwitching = viewSwitching;
                        }
window.getToggleCategory = getToggleCategory;
                    } else {
                        $toggleElement.show();
/* == Apply four functions defined above == */
                        if (rootElement.classList.contains("list-switcher-collapsibility-suppressed")) {
mw.hook("wikipage.content").add(function($content) {
                            rootElement.classList.remove("list-switcher-collapsibility-suppressed");
// NavToggles
                            rootElement.classList.add("list-switcher-collapsed");
$(".NavFrame", $content).each(function(){
                        }
createNavToggle(this);
                    }
});
                }
$(".inflection-table-collapsible", $content).each(function(){
            });
createNavToggleForInflectionTable(this);
 
});
            resizeObserver.observe(termList);
        }
// order nyms -> usexes -> quotes, to match the conventional order in entries
    }
 
// synonyms and such under definitions
    function setupNyms(index, dlTag) {
// if (mw.config.get("wgNamespaceNumber") === 0) {
        var relationClasses = ["synonym", "antonym", "hypernym", "hyponym", "meronym",
$("dl:has(dd > .nyms)", $content).each(setupNyms);
            "holonym", "troponym", "comeronym", "coordinate-term",
// }
            "near-synonym", "imperfective", "perfective", "alternative-form"];
 
// usage examples and collocations
        var relations = $(dlTag).find("dd > .nyms").get().filter(
var namespaceNumber = mw.config.get("wgNamespaceNumber");
            function (element) {
if (window.defaultVisibilityTogglesForUsageExamples) {
                return Array.prototype.some.call(element.classList, function (className) {
if (namespaceNumber === 0) {
                    if (relationClasses.indexOf(className) !== -1) {
$("ol > li dl:has(dd > .h-usage-example)", $content).each(setupUsageExampleCollapses);
                        element.dataset.relationClass = className;
}
                        return true;
}
                    }
                });
// quotes
            });
if (namespaceNumber === 0 || namespaceNumber === 100 || namespaceNumber === 118) {
 
// First, find all the ordered lists, i.e. all the series of definitions.
        function setupToggle(elements, category, visibleByDefault) {
$("ol > li", $content).each(function(){
            if (elements.length === 0) return null;
setupHiddenQuotes(this);
            var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
});
            var text = elements.map(function (e) {
}
                var linkCount = e.querySelectorAll("span[lang]").length;
                return e.dataset.relationClass.replace("-", " ") +
//view switching
                    (linkCount > 1 ? "s" : "");
$(".vsSwitcher", $content).each(function(){
            }).join(", ");
viewSwitching(this);
 
});
            function show() {
                toggler.text(text + nbsp + "▲");
// list switching
                $(dlTag).show();
$(".list-switcher", $content).each(function () {
                $(elements).show();
enableListSwitchGeneric(this);
            }
});
            function hide() {
});
                toggler.text(text + nbsp + "▼");
                if ($(dlTag).children().length === elements.length) {
jQuery(mw).on("LivePreviewDone", function (ev, sels) {
                    $(dlTag).hide();
var ols = jQuery(sels.join(",")).find("ol");
                } else {
for (var i = 0; i < ols.length; i++) {
                    $(elements).hide();
for (var j = 0; j < ols[i].childNodes.length; j++) {
                }
var li = ols[i].childNodes[j];
            }
if (li.nodeName.toUpperCase() == "LI") {
 
setupHiddenQuotes(li);
            $(dlTag).before($("<span>")
}
                .addClass("nyms-toggle")
}
                .attr("data-nosnippet", "")
}
                .append(toggler)
});
                .css("margin-left", "5px"));
 
            toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
        }
 
        var synonyms = relations.filter(function (e) {
            return ["synonym", "antonym", "near-synonym", "coordinate-term", "alternative-form"].indexOf(e.dataset.relationClass) !== -1;
        });
        var other = relations.filter(function (e) { return synonyms.indexOf(e) === -1; });
 
        setupToggle(synonyms, "synonyms", true);
        setupToggle(other, "semantic relations");
    }
 
    function setupUsageExampleCollapses(index, dlTag) {
        var usexTags = $(dlTag).find("dd > .h-usage-example").get();
 
        function setupToggle(elements, category, visibleByDefault) {
            if (elements.length === 0) return null;
            var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
 
            function show() {
                toggler.text(category + nbsp + "▲");
                $(dlTag).show();
                $(elements).show();
            }
            function hide() {
                toggler.text(category + nbsp + "▼");
                if ($(dlTag).children().length === elements.length) {
                    $(dlTag).hide();
                } else {
                    $(elements).hide();
                }
            }
 
            $(dlTag).before($("<span>")
                .addClass("nyms-toggle")
                .append(toggler)
                .css("margin-left", "5px"));
 
            toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
        }
 
        var collocations = usexTags.filter(function (e) {
            return $(e).hasClass("collocation");
        });
        var usexes = usexTags.filter(function (e) { return collocations.indexOf(e) === -1; });
 
        setupToggle(usexes, "usage examples", true);
        setupToggle(collocations, "collocations", true);
    }
 
    window.createNavToggle = createNavToggle;
    window.setupHiddenQuotes = setupHiddenQuotes;
    window.viewSwitching = viewSwitching;
    window.getToggleCategory = getToggleCategory;
 
    mw.hook("wikipage.content").add(function ($content) {
        $(".NavFrame", $content).each(function () {
            createNavToggle(this);
        });
        $(".inflection-table-collapsible", $content).each(function () {
            createNavToggleForInflectionTable(this);
        });
 
        $("dl:has(dd > .nyms)", $content).each(setupNyms);
 
        var namespaceNumber = mw.config.get("wgNamespaceNumber");
        if (window.defaultVisibilityTogglesForUsageExamples) {
            if (namespaceNumber === 0) {
                $("ol > li dl:has(dd > .h-usage-example)", $content).each(setupUsageExampleCollapses);
            }
        }
 
        if (namespaceNumber === 0 || namespaceNumber === 100 || namespaceNumber === 118) {
            $("ol > li", $content).each(function () {
                setupHiddenQuotes(this);
            });
        }
 
        $(".vsSwitcher", $content).each(function () {
            viewSwitching(this);
        });
 
        $(".list-switcher", $content).each(function () {
            enableListSwitchGeneric(this);
        });
    });
 
    jQuery(mw).on("LivePreviewDone", function (ev, sels) {
        var ols = jQuery(sels.join(",")).find("ol");
        for (var i = 0; i < ols.length; i++) {
            for (var j = 0; j < ols[i].childNodes.length; j++) {
                var li = ols[i].childNodes[j];
                if (li.nodeName.toUpperCase() == "LI") {
                    setupHiddenQuotes(li);
                }
            }
        }
    });
})();
})();

Latest revision as of 22:53, 21 November 2025

/* jshint undef: true */
/* globals $, jQuery, mw, window, getComputedStyle */

(function defaultVisibilityTogglesIIFE() {
	"use strict";
	
	if (window.noDefaultVisibilityToggles) return;
	
	/* == NavBars == */
	var NavigationBarHide = "hide ▲";
	var NavigationBarShow = "show ▼";
	
	var nbsp = "\u00a0";
	
	// Check if an element has been activated with a toggle.
	// For convenience, this has the side effect of marking the element as having
	// a toggle, if it is not already marked.
	// Allows the functions to avoid toggleifying elements more than once, which
	// can lead to multiple "show" buttons, for instance.
	// The argument must be an Element, not a jQuery object.
	function checkAndSetToggleified(element) {
		if (element.isToggleified) {
			return true;
		}
		element.isToggleified = true;
	}
	
	function getToggleCategory(element, defaultCategory) {
		if ($(element).find("table").first().is(".translations"))
			return "translations";
		
		var heading = element;
		while ((heading = heading.previousElementSibling)) {
			// tagName is always uppercase:
			// https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName
			var num = heading.tagName.match(/H(\d)/);
			if (num)
				num = Number(num[1]);
			else
				continue;
			if (4 <= num && num <= 6) {
				if (heading.getElementsByTagName("span")[1])
					heading = heading.getElementsByTagName("span")[0];
				var text = jQuery(heading).text()
					.toLowerCase()
					// jQuery's .text() is inconsistent about whitespace:
					.replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ")
					// remove numbers added by the "Auto-number headings" pref:
					.replace(/^[1-9][0-9.]+ ?/, "");
				// Toggle category must be convertible to a valid CSS identifier so
				// that it can be used in an id selector in jQuery in
				// ToggleCategory.prototype.newSidebarToggle
				// in [[MediaWiki:Gadget-VisibilityToggles.js]].
				// Spaces must later be converted to hyphens or underscores.
				// Reference: https://drafts.csswg.org/selectors-4/#id-selectors
				if (/^[a-zA-Z0-9\s_-]+$/.test(text))
					return text;
				else
					break;
			} else if (num)
				break;
		}
		
		return defaultCategory;
	}
	
	function createNavToggle(navFrame) {
		if (checkAndSetToggleified(navFrame)) {
			return;
		}
		
		var navHead, navContent;
		for (var i = 0, children = navFrame.childNodes; i < children.length; ++i) {
			var child = children[i];
			if (child.nodeName === "DIV") {
				var classList = child.classList;
				if (classList.contains("NavHead"))
					navHead = child;
				if (classList.contains("NavContent"))
					navContent = child;
			}
		}
		if (!(navHead && navContent))
			return;
		
		// Step 1, don't react when a subitem is clicked.
		$(navHead).find("a").on("click", function (e) {
			e.stopPropagation();
			e.stopImmediatePropagation();
		});
				
		// Step 2, toggle visibility when bar is clicked.
		// NOTE This function was chosen due to some funny behaviour in Safari.
		var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
		
		$("<span>").addClass("NavToggle").attr("data-nosnippet", "")
			.append($navToggle)
			.prependTo(navHead);
		
		navHead.style.cursor = "pointer";
		var toggleCategory = $(navFrame).data("toggle-category")
			|| getToggleCategory(navFrame, "other boxes");
		navHead.onclick = window.VisibilityToggles.register(toggleCategory,
			function show() {
				$navToggle.text(NavigationBarHide);
				if (navContent)
					navContent.style.display = "block";
			},
			function hide() {
				$navToggle.text(NavigationBarShow);
				if (navContent)
					navContent.style.display = "none";
			});
	}
	
	function createNavToggleForInflectionTable(it) {
		if (checkAndSetToggleified(it)) {
			return;
		}
		
		// The table caption is the clickable element
		var itCaption = $(it).find("caption").get(0);
		
		// Step 1, don't react when a subitem is clicked.
		$(itCaption).find("a").on("click", function (e) {
			e.stopPropagation();
			e.stopImmediatePropagation();
		});
				
		// Step 2, toggle visibility when bar is clicked.
		// NOTE This function was chosen due to some funny behaviour in Safari.
		var $navToggle = $("<a>").attr("role", "button").attr("tabindex", "0");
		
		$("<span>").addClass("NavToggle").attr("data-nosnippet", "")
			.append($navToggle)
			.prependTo(itCaption);
		
		itCaption.style.cursor = "pointer";
		var toggleCategory = $(it).data("toggle-category")
			|| getToggleCategory(it, "other boxes");
		itCaption.onclick = window.VisibilityToggles.register(toggleCategory,
			function show() {
				$navToggle.text(NavigationBarHide);
				if (it) {
					it.classList.remove("inflection-table-collapsed");
				}
			},
			function hide() {
				$navToggle.text(NavigationBarShow);
				if (it) {
					it.classList.add("inflection-table-collapsed");
				}
			});
			
		// Check to see if we are on a browser that is known to support
		// visibility: collapse, which permits inflection table headings to wrap.
		// WebKit needs to be special-cased, as technically it does support
		// visibility: collapse, but it just implements it as a synonym for
		// visibility: hidden, which is useless. (as of November 2024)
		// Yes, I know User-Agent sniffing is so 2004... but WebKit is the new IE
		if (
			CSS && CSS.supports && CSS.supports("visibility:collapse") &&
			// exclude WebKit/Safari, excepting Blink engines which have a frozen WebKit version number
			(navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1)
		) {
			it.classList.remove("no-vc");
		} else {
			// Strange behaviour occurs when you set the table caption to nowrap
			// The [show/hide] toggle crashes into the caption text
			// This spacer element prevents that
			$("<span>").addClass("no-vc-spacer").appendTo(itCaption);
		}
	}
	
	/* ==Hidden Quotes== */
	function setupHiddenQuotes(li) {
		if (checkAndSetToggleified(li))
			return;
		
		let HQToggleButton, liComp, dl;

		function show() {
			HQToggleButton.text("quotations ▲");
			$(li).children("ul").show();
		}
		function hide() {
			HQToggleButton.text("quotations ▼");
			$(li).children("ul").hide();
		}
		
		for (const liComp of li.childNodes) {
			// Look at each component of the definition.
			if (liComp.tagName === "DL" && !dl)
				dl = liComp;

			// If we find a ul or dl, we have quotes or example sentences, and thus need a button.
			if (liComp.tagName === "UL") {
				$(li).children("ul").addClass("wikt-quote-container");
				HQToggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
				$(dl || liComp).before($("<span>").addClass("HQToggle").attr("data-nosnippet", "").append(HQToggleButton).css("margin-left", "5px"));
				HQToggleButton.on("click", window.VisibilityToggles.register("quotations", show, hide));
				break;
			}
		}
	}
	
	/* == View Switching == */
	
	function viewSwitching(rootElement) {
		if (checkAndSetToggleified(rootElement)) {
			return;
		}
		
		var $rootElement = $(rootElement);
		var showButtonText = $rootElement.data("vs-showtext") || "more ▼";
		var hideButtonText = $rootElement.data("vs-hidetext") || "less ▲";
		
		var toSkip = $rootElement.find(".vsSwitcher").find("*");
		var elemsToHide = $rootElement.find(".vsHide").not(toSkip);
		var elemsToShow = $rootElement.find(".vsShow").not(toSkip);
		
		// Find the element to place the toggle button in.
		var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first();
		
		// The toggleElement becomes clickable in its entirety, but
		// we need to prevent this if a contained link is clicked instead.
		toggleElement.find("a").on("click", function (e) {
			e.stopPropagation();
			e.stopImmediatePropagation();
		});
		
		// Add the toggle button.
		var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
		
		$("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement);
		
		// Determine the visibility toggle category (for the links in the bar on the left).
		var toggleCategory = $rootElement.data("toggle-category");
		if (!toggleCategory) {
			var classNames = $rootElement.attr("class").split(/\s+/);
			
			for (var i = 0; i < classNames.length; ++i) {
				var className = classNames[i].split("-");
				
				if (className[0] == "vsToggleCategory") {
					toggleCategory = className[1];
				}
			}
		}
		
		if (!toggleCategory)
			toggleCategory = "others";
		
		// Register the visibility toggle.
		toggleElement.css("cursor", "pointer");
		toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
			function show() {
				toggleButton.text(hideButtonText);
				elemsToShow.hide();
				elemsToHide.show();
			},
			function hide() {
				toggleButton.text(showButtonText);
				elemsToShow.show();
				elemsToHide.hide();
			}));
	}
	
	/* ==List switching== */
	function enableListSwitchGeneric(rootElement) {
		if (checkAndSetToggleified(rootElement)) {
			return;
		}
		
		var $rootElement = $(rootElement);
		
		// Create a toggle button.
		var $toggleElement = $("<div>").addClass("list-switcher-element");
		var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", "");
		var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");
		
		// Add the toggle button to the DOM tree.
		$navToggle.append($toggleButton).prependTo($toggleElement);
		$toggleElement.insertAfter($rootElement);
		$toggleElement.show();
		
		// Determine the visibility toggle category (for the links in the bar on the
		// left). It will either be the value of the "data-toggle-category"
		// attribute or will be based on the text of the closest preceding
		// fourth-to-sixth-level header.
		var toggleCategory = $rootElement.data("toggle-category")
			|| getToggleCategory($rootElement[0], "other lists");
		
		// Determine the text for the $toggleButton.
		var showButtonText = "show more ▼";
		var hideButtonText = "show less ▲";
		var numItems;
		// special handling for [[Module:collapsible category tree]]
		var $categoryTreeTag = $rootElement.children(".CategoryTreeTag");
		if ($categoryTreeTag) {
			if ($categoryTreeTag.attr("data-pages-left-over") !== "0") {
				// some category members are omitted from the list (MediaWiki limitation)
				// just use basic "show more/less" in this case for now, this is a big change
				//showButtonText = "show first 200 of " + $categoryTreeTag.attr("data-pages-in-cat") + " ▼";
				//hideButtonText = "show fewer ▲";
			} else {
				// all category members are included in the list
				numItems = $categoryTreeTag.attr("data-pages-in-cat");
			}
		} else {
			// standard list-switcher using <li> elements
			numItems = $rootElement.find("li").length;
		}
		if (numItems) {
			showButtonText = "show all " + numItems + " ▼";
			hideButtonText = "show fewer ▲";	
		}
		
		// Register the visibility toggle.
		$toggleElement.on("click", window.VisibilityToggles.register(toggleCategory,
			function show() {
				$toggleButton.text(hideButtonText);
				if (rootElement) {
					rootElement.classList.remove("list-switcher-collapsed");
				}
			},
			function hide() {
				$toggleButton.text(showButtonText);
				if (rootElement) {
					rootElement.classList.add("list-switcher-collapsed");
				}
			}));
			
		// Register a resize observer to see if we need to keep the
		// show/hide toggle visible
		var termList = rootElement.querySelector(':scope > .term-list');
		if (termList && window.ResizeObserver) {
			var resizeObserver = new ResizeObserver(function(entries) {
				if (entries[0] && entries[0].contentBoxSize[0]) {
					// Work out what the max-height would be, in pixels
					// As a hack, this value is stored in the CSS `bottom`
					// property, as `max-height` is only in place when
					// the list is collapsed, but we need to do this check
					// even when the list is not collapsed
					var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom);
					
					// If box height is less than its max height + 20 px, suppress
					// collapsibility. The 20 px buffer prevents the situation where
					// clicking "show more" expands the box by just a few pixels
					if (entries[0].contentBoxSize[0].blockSize <= maxHeightPx + 20) {
						$toggleElement.hide();
						if (rootElement.classList.contains("list-switcher-collapsed")) {
							rootElement.classList.remove("list-switcher-collapsed");
							rootElement.classList.add("list-switcher-collapsibility-suppressed");
						}
					} else {
						$toggleElement.show();
						if (rootElement.classList.contains("list-switcher-collapsibility-suppressed")) {
							rootElement.classList.remove("list-switcher-collapsibility-suppressed");
							rootElement.classList.add("list-switcher-collapsed");
						}
					}
				}
			});
			
			resizeObserver.observe(termList);
		}
	}
	
	// based on [[User:Erutuon/scripts/semhide.js]], [[User:Jberkel/semhide.js]],
	// [[User:Ungoliant_MMDCCLXIV/synshide.js]]
	function setupNyms(index, dlTag) {
		// [[Wiktionary:Semantic relations]]
		var relationClasses = [ "synonym", "antonym", "hypernym", "hyponym", "meronym",
								"holonym", "troponym", "comeronym", "coordinate-term",
								"near-synonym", "imperfective", "perfective", "alternative-form" ];
		
		var relations = $(dlTag).find("dd > .nyms").get().filter(
			function(element) {
				return Array.prototype.some.call(element.classList, function (className) {
					if (relationClasses.indexOf(className) !== -1) {
						element.dataset.relationClass = className;
						return true;
					}
				});
			});
		
		function setupToggle(elements, category, visibleByDefault) {
			if (elements.length === 0) return null;
			var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
			var text = elements.map(function (e) {
				var linkCount = e.querySelectorAll("span[lang]").length;
				return e.dataset.relationClass.replace("-", " ") +
						(linkCount > 1 ? "s" : "");
			}).join(", ");
			
			function show() {
				toggler.text(text + nbsp + "▲");
				$(dlTag).show();
				$(elements).show();
			}
			function hide() {
				toggler.text(text + nbsp + "▼");
				if ($(dlTag).children().length === elements.length) {
					$(dlTag).hide();
				} else {
					$(elements).hide();
				}
			}
		
			$(dlTag).before($("<span>")
				.addClass("nyms-toggle")
				.attr("data-nosnippet", "")
				.append(toggler)
				.css("margin-left", "5px"));
				
			toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
		}
		
		var synonyms = relations.filter(function (e) {
			return ["synonym", "antonym", "near-synonym", "coordinate-term", "alternative-form"].indexOf(e.dataset.relationClass) !== -1;
		});
		var other = relations.filter(function (e) { return synonyms.indexOf(e) === -1; });
		
		setupToggle(synonyms, "synonyms", true /* show by default  */);
		setupToggle(other, "semantic relations");
	}
	
	
	function setupUsageExampleCollapses(index, dlTag) {
		var usexTags = $(dlTag).find("dd > .h-usage-example").get();
		
		function setupToggle(elements, category, visibleByDefault) {
			if (elements.length === 0) return null;
			var toggler = $("<a>").attr("role", "button").attr("tabindex", "0");
			
			function show() {
				toggler.text(category + nbsp + "▲");
				$(dlTag).show();
				$(elements).show();
			}
			function hide() {
				toggler.text(category + nbsp + "▼");
				if ($(dlTag).children().length === elements.length) {
					$(dlTag).hide();
				} else {
					$(elements).hide();
				}
			}
		
			$(dlTag).before($("<span>")
				.addClass("nyms-toggle")
				.append(toggler)
				.css("margin-left", "5px"));
				
			toggler.click(window.VisibilityToggles.register(category, show, hide, visibleByDefault));
		}
		
		var collocations = usexTags.filter(function (e) {
			return $(e).hasClass("collocation");
		});
		var usexes = usexTags.filter(function (e) { return collocations.indexOf(e) === -1; });
		
		setupToggle(usexes, "usage examples", true /* show by default */);
		setupToggle(collocations, "collocations", true /* show by default */);
	}
	
	
	window.createNavToggle = createNavToggle;
	window.setupHiddenQuotes = setupHiddenQuotes;
	window.viewSwitching = viewSwitching;
	window.getToggleCategory = getToggleCategory;
	
	/* == Apply four functions defined above == */
	mw.hook("wikipage.content").add(function($content) {
		// NavToggles
		$(".NavFrame", $content).each(function(){
			createNavToggle(this);
		});
		$(".inflection-table-collapsible", $content).each(function(){
			createNavToggleForInflectionTable(this);
		});
		
		// order nyms -> usexes -> quotes, to match the conventional order in entries
		
		// synonyms and such under definitions
		// if (mw.config.get("wgNamespaceNumber") === 0) {
			$("dl:has(dd > .nyms)", $content).each(setupNyms);
		// }
		
		// usage examples and collocations
		var namespaceNumber = mw.config.get("wgNamespaceNumber");
		if (window.defaultVisibilityTogglesForUsageExamples) {
			if (namespaceNumber === 0) {
				$("ol > li dl:has(dd > .h-usage-example)", $content).each(setupUsageExampleCollapses);
			}
		}
	
		// quotes
		if (namespaceNumber === 0 || namespaceNumber === 100 || namespaceNumber === 118) {
			// First, find all the ordered lists, i.e. all the series of definitions.
			$("ol > li", $content).each(function(){
				setupHiddenQuotes(this);
			});
		}
	
		//view switching
		$(".vsSwitcher", $content).each(function(){
			viewSwitching(this);
		});
	
		// list switching
		$(".list-switcher", $content).each(function () {
			enableListSwitchGeneric(this);
		});
	});
	
	jQuery(mw).on("LivePreviewDone", function (ev, sels) {
		var ols = jQuery(sels.join(",")).find("ol");
		for (var i = 0; i < ols.length; i++) {
			for (var j = 0; j < ols[i].childNodes.length; j++) {
				var li = ols[i].childNodes[j];
				if (li.nodeName.toUpperCase() == "LI") {
					setupHiddenQuotes(li);
				}
			}
		}
	});
})();