MediaWiki:Gadget-defaultVisibilityToggles.js

From Linguifex
Revision as of 13:05, 15 November 2025 by Sware (talk | contribs)
Jump to navigation Jump to search

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.
/* jshint undef: true, esversion: 5 */
/* globals $, jQuery, mw, window, getComputedStyle */


(function () {
    "use strict";

    if (window.noDefaultVisibilityToggles) return;

    var NavigationBarHide = "hide ▲";
    var NavigationBarShow = "show ▼";

    var nbsp = "\u00a0";

    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)) {
            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()
                    .replace(/^\s+|\s+$/g, "").replace(/\s+/g, " ")
                    .replace(/^[1-9][0-9.]+ ?/, "");
                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;
        var children = navFrame.childNodes;
        for (var i = 0; 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;

        $(navHead).find("a").on("click", function (e) {
            e.stopPropagation();
            e.stopImmediatePropagation();
        });

        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;
        }

        var itCaption = $(it).find("caption").get(0);

        $(itCaption).find("a").on("click", function (e) {
            e.stopPropagation();
            e.stopImmediatePropagation();
        });

        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");
                }
            });

        if (
            CSS && CSS.supports && CSS.supports("visibility:collapse") &&
            (navigator.userAgent.indexOf("AppleWebKit/") === -1 || navigator.userAgent.indexOf("AppleWebKit/537.36") > -1)
        ) {
            it.classList.remove("no-vc");
        } else {
            $("<span>").addClass("no-vc-spacer").appendTo(itCaption);
        }
    }

    function setupHiddenQuotes(li) {
        if (checkAndSetToggleified(li))
            return;

        var HQToggleButton, dl;

        function show() {
            HQToggleButton.text("quotations ▲");
            $(li).children("ul").show();
        }
        function hide() {
            HQToggleButton.text("quotations ▼");
            $(li).children("ul").hide();
        }

        var liComp;
        for (var i = 0; i < li.childNodes.length; i++) {
            liComp = li.childNodes[i];
            if (liComp.tagName === "DL" && !dl)
                dl = liComp;
            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;
            }
        }
    }

    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);

        var toggleElement = $rootElement.find(".vsToggleElement").not(toSkip).first();

        toggleElement.find("a").on("click", function (e) {
            e.stopPropagation();
            e.stopImmediatePropagation();
        });

        var toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");

        $("<span>").addClass("NavToggle").attr("data-nosnippet", "").append(toggleButton).prependTo(toggleElement);

        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";

        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();
            }));
    }

    function enableListSwitchGeneric(rootElement) {
        if (checkAndSetToggleified(rootElement)) {
            return;
        }

        var $rootElement = $(rootElement);

        var $toggleElement = $("<div>").addClass("list-switcher-element");
        var $navToggle = $("<span>").addClass("NavToggle").attr("data-nosnippet", "");
        var $toggleButton = $("<a>").attr("role", "button").attr("tabindex", "0");

        $navToggle.append($toggleButton).prependTo($toggleElement);
        $toggleElement.insertAfter($rootElement);
        $toggleElement.show();

        var toggleCategory = $rootElement.data("toggle-category") || getToggleCategory($rootElement[0], "other lists");

        var showButtonText = "show more ▼";
        var hideButtonText = "show less ▲";
        var numItems;
        var $categoryTreeTag = $rootElement.children(".CategoryTreeTag");
        if ($categoryTreeTag) {
            if ($categoryTreeTag.attr("data-pages-left-over") !== "0") {
            } else {
                numItems = $categoryTreeTag.attr("data-pages-in-cat");
            }
        } else {
            numItems = $rootElement.find("li").length;
        }
        if (numItems) {
            showButtonText = "show all " + numItems + " ▼";
            hideButtonText = "show fewer ▲";
        }

        $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");
                }
            }));

        var termList = rootElement.querySelector(':scope > .term-list');
        if (termList && window.ResizeObserver) {
            var resizeObserver = new ResizeObserver(function (entries) {
                if (entries[0] && entries[0].contentBoxSize[0]) {
                    var maxHeightPx = parseFloat(getComputedStyle(rootElement).bottom);

                    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);
        }
    }

    function setupNyms(index, dlTag) {
        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);
        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);
                }
            }
        }
    });
})();