MediaWiki:Common.js:修订间差异

跳到导航 跳到搜索
添加498字节 、​ 2022年5月4日 (星期三)
无编辑摘要
无编辑摘要
无编辑摘要
第111行: 第111行:
/////// Toggle Content
/////// Toggle Content
if(true) {
if(true) {
    const cssSanitizer = (cssStr) => (typeof cssStr === "string" ? cssStr : "").replace(RegExp(decodeURIComponent("%3C!--"), "g"), "").replace(RegExp(decodeURIComponent("-%3E"), "g"), "").replace(/\/\//g, "").replace(/url/g, "").replace(/&/g, "").replace(/pointer-event/g, ";").replace(/display\s*:\s*none\s*!\s*important/g, "display: none");
    const cssSanitizer = (cssStr) => {
    const uuidv4 = () => {
         let result = "";
         let result = "";
         while (result === "" || $(`#${result}, [name="${result}"]`).length > 0) {
         if (typeof cssStr === "string") {
             result = ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
             result = cssStr;
                (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
            );
         }
         }
        result = result.replace(RegExp(decodeURIComponent("%3C!--"), "g"), "");
        result = result.replace(RegExp(decodeURIComponent("-%3E"), "g"), "");
        result = result.replace(/\/\//g, "");
        result = result.replace(/url/g, "");
        result = result.replace(/&/g, "");
        result = result.replace(/pointer-event/g, ";");
        result = result.replace(/display\s*:\s*none\s*!\s*important/g, "display: none");
         return result;
         return result;
    };
    }
    const datasetParser = (ele) => {
    const uuidv4 = () => {
        const result = {
        let result = "";
            config: {},
        while (result === "" || $(`#${result}, [name="${result}"]`).length > 0) {
            data: {},
            result = ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
        };
                (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        Object.entries(ele.dataset).filter(([n, m]) => n.startsWith("key-") && !/['"<>\\/]/.test(m)).forEach(([__key, _key]) => {
            );
            const value = ele.dataset[`value-${__key.substring(4)}`];
        }
            if (_key.length > 0 && value.length > 0) {
        return result;
                const isConfig = _key.startsWith("@");
    };
                const key = isConfig ? _key.substring(1) : _key;
    const datasetParser = (ele) => {
                const base = result[isConfig ? "config" : "data"];
        const result = {
                base[key] = value;
            config: {},
                if (/@o(?:n|ff)$/.test(_key)) {
            data: {},
                    const id = _key.replace(/@o(?:n|ff)$/, "");
        };
                    if (!(id in base)) {
        Object.entries(ele.dataset).filter(([n, m]) => n.startsWith("key-") && !/['"<>\\/]/.test(m)).forEach(([__key, _key]) => {
                        base[id] = value;
            const value = ele.dataset[`value-${__key.substring(4)}`];
                    }
            if (_key.length > 0 && value.length > 0) {
                } else if (_key.endsWith("@input")) {
                const isConfig = _key.startsWith("@");
                    base[_key] = value;
                const key = isConfig ? _key.substring(1) : _key;
                    const id = _key.replace(/@input$/, "");
                const base = result[isConfig ? "config" : "data"];
                    if (!(id in base)) {
                base[key] = value;
                        base[id] = "";
                if (/@o(?:n|ff)$/.test(_key)) {
                    }
                    const id = _key.replace(/@o(?:n|ff)$/, "");
                } else {
                    if (!(id in base)) {
                    if (!(`${key}@on` in base)) {
                        base[id] = value;
                        base[`${key}@on`] = value;
                    }
                    }
                } else if (_key.endsWith("@input")) {
                    if (!(`${key}@off` in base)) {
                    base[_key] = value;
                        base[`${key}@off`] = value;
                    const id = _key.replace(/@input$/, "");
                    }
                    if (!(id in base)) {
                    if (!(`${key}@input` in base)) {
                        base[id] = "";
                        base[`${key}@input`] = "";
                    }
                    }
                } else {
                }
                    if (!(`${key}@on` in base)) {
            }
                        base[`${key}@on`] = value;
        });
                    }
        return result;
                    if (!(`${key}@off` in base)) {
    };
                        base[`${key}@off`] = value;
    const getEntries = (obj) => Object.entries(obj).filter(([k, n]) => !/@(?:on|off|input)$/.test(k) && !/['"<>\\/]/.test(n));
                    }
    const triggerChangeHandler = ($ele) => {
                    if (!(`${key}@input` in base)) {
        $ele.each((_, ele) => {
                        base[`${key}@input`] = "";
            $(ele).triggerHandler("change", [true]);
                    }
        });
                }
    };
            }
    const textToggleDisplayStyle = {};
        });
    $(".textToggleDisplayStyle").each((_, ele) => {
        return result;
        const dataset = datasetParser(ele).data;
    };
        getEntries(dataset).forEach(([id, style]) => {
    const getEntries = (obj) => Object.entries(obj).filter(([k, n]) => !/@(?:on|off|input)$/.test(k) && !/['"<>\\/]/.test(n));
            textToggleDisplayStyle[id] = style;
    const triggerChangeHandler = ($ele) => {
        });
        $ele.each((_, ele) => {
    });
            $(ele).triggerHandler("change", [true]);
    $(".textToggleDisplay").each((_, ele) => {
        });
        if (ele.dataset.id in textToggleDisplayStyle) {
    };
            $(ele).attr("style", cssSanitizer(textToggleDisplayStyle[ele.dataset.id]));
    const textToggleDisplayStyle = {};
        }
    $(".textToggleDisplayStyle").each((_, ele) => {
    }).addClass("hidden");
        const dataset = datasetParser(ele).data;
    $(".textToggleDisplayButtons").each((_, ele) => {
        getEntries(dataset).forEach(([id, style]) => {
        const self = $(ele);
            textToggleDisplayStyle[id] = style;
        const parsedDataset = datasetParser(ele);
        });
        const ifRadio = "radio" in parsedDataset.config && parsedDataset.config.radio.length > 0;
    });
        const ifForceNoCancel = "forceNoCancel" in parsedDataset.config && parsedDataset.config.forceNoCancel.length > 0;
    $(".textToggleDisplay").each((_, ele) => {
        const ifReverse = "reverse" in parsedDataset.config && parsedDataset.config.reverse.length > 0;
        if (ele.dataset.id in textToggleDisplayStyle) {
        const name = uuidv4();
            $(ele).attr("style", cssSanitizer(textToggleDisplayStyle[ele.dataset.id]));
        let hasDefault = false;
        }
        self.children("span[data-key]").each((_, e) => {
    }).addClass("hidden");
            if (/['"<>\\/]/.test(e.dataset.key)) {
    $(".textToggleDisplayButtons").each((_, ele) => {
                e.remove();
        const self = $(ele);
                return;
        const parsedDataset = datasetParser(ele);
            }
        const ifRadio = "radio" in parsedDataset.config && parsedDataset.config.radio.length > 0;
            const $e = $(e);
        const ifForceNoCancel = "forceNoCancel" in parsedDataset.config && parsedDataset.config.forceNoCancel.length > 0;
            const input = $("<input/>");
        const ifReverse = "reverse" in parsedDataset.config && parsedDataset.config.reverse.length > 0;
            input.attr({
        const name = uuidv4();
                "data-id": e.dataset.key,
        let hasDefault = false;
                type: ifRadio ? "radio" : "checkbox",
        self.children("span[data-key]").each((_, e) => {
            }).addClass(ifReverse ? "textToggleDisplayButtonInputReverse" : "textToggleDisplayButtonInput");
            if (/['"<>\\/]/.test(e.dataset.key)) {
            if (ifRadio) {
                e.remove();
                input.attr("name", name);
                return;
            }
            }
            const label = $("<label/>");
            const $e = $(e);
            $e.children().appendTo(label);
            const input = $("<input/>");
            label.prepend(input).appendTo(e).attr("data-id", e.dataset.key).addClass("textToggleDisplayButtonLabel");
            input.attr({
            $e.find("*").each((_, e) => {
                "data-id": e.dataset.key,
                e.addEventListener("click", (evt) => {
                type: ifRadio ? "radio" : "checkbox",
                    evt.stopImmediatePropagation();
            }).addClass(ifReverse ? "textToggleDisplayButtonInputReverse" : "textToggleDisplayButtonInput");
                    evt.stopPropagation();
            if (ifRadio) {
                    if (!$(evt.target).is(input)) {
                input.attr("name", name);
                        evt.preventDefault();
            }
                        if (ifRadio ? !input.prop("checked") : true) {
            const label = $("<label/>");
                            input.prop("checked", !input.prop("checked")).trigger("change");
            $e.children().appendTo(label);
                        }
            label.prepend(input).appendTo(e).attr("data-id", e.dataset.key).addClass("textToggleDisplayButtonLabel");
                    }
            $e.find("*").each((_, e) => {
                }, {
                e.addEventListener("click", (evt) => {
                    capture: true,
                    evt.stopImmediatePropagation();
                });
                    evt.stopPropagation();
            });
                    if (!$(evt.target).is(input)) {
            if (e.dataset.key === parsedDataset.config.default) {
                        evt.preventDefault();
                input.prop("checked", true);
                        if (ifRadio ? !input.prop("checked") : true) {
                hasDefault = true;
                            input.prop("checked", !input.prop("checked")).trigger("change");
            }
                        }
        });
                    }
        if (ifRadio && (!hasDefault || !ifForceNoCancel)) {
                }, {
            const input = $("<input/>");
                    capture: true,
            const inputId = uuidv4();
                });
            input.attr({
            });
                "data-id": "",
            if (e.dataset.key === parsedDataset.config.default) {
                "data-radio-cancel": "true",
                input.prop("checked", true);
                id: inputId,
                hasDefault = true;
                name,
            }
                type: "radio",
        });
            }).addClass(ifReverse ? "textToggleDisplayButtonInputReverse" : "textToggleDisplayButtonInput").css({
        if (ifRadio && (!hasDefault || !ifForceNoCancel)) {
                "margin-left": "0",
            const input = $("<input/>");
                "margin-right": "0",
            const inputId = uuidv4();
                width: "0",
            input.attr({
            });
                "data-id": "",
            const label = $("<label/>");
                "data-radio-cancel": "true",
            const span = $("<span/>");
                id: inputId,
            span.text("取消选择");
                name,
            label.attr({
                type: "radio",
                "data-id": "",
            }).addClass(ifReverse ? "textToggleDisplayButtonInputReverse" : "textToggleDisplayButtonInput").css({
                "for": inputId,
                "margin-left": "0",
            }).addClass("textToggleDisplayButtonLabel cancelButton");
                "margin-right": "0",
            self.append(label.append(input).append(span));
                width: "0",
            if (!hasDefault) {
            });
                input.prop("checked", true);
            const label = $("<label/>");
            }
            const span = $("<span/>");
        }
            span.text("取消选择");
    });
            label.attr({
    $(".textToggleDisplayButtonsStyle").each((_, ele) => {
                "data-id": "",
        const parsedDataset = datasetParser(ele);
                "for": inputId,
        $(".textToggleDisplayButtonLabel.cancelButton").attr({
            }).addClass("textToggleDisplayButtonLabel cancelButton");
            "data-style-off": parsedDataset.config["cancel@off"] || "",
            self.append(label.append(input).append(span));
            "data-style-on": parsedDataset.config["cancel@on"] || "",
            if (!hasDefault) {
        });
                input.prop("checked", true);
        $(".textToggleDisplayButtonLabel.cancelButton > input").attr("style", cssSanitizer(parsedDataset.config["cancel@input"]));
            }
        getEntries(parsedDataset.data).forEach(([id]) => {
        }
            $(`.textToggleDisplayButtonLabel[data-id="${id}"]`).attr({
    });
                "data-style-off": parsedDataset.data[`${id}@off`] || "",
    $(".textToggleDisplayButtonsStyle").each((_, ele) => {
                "data-style-on": parsedDataset.data[`${id}@on`] || "",
        const parsedDataset = datasetParser(ele);
            }).children("input").attr("style", cssSanitizer(parsedDataset.data[`${id}@input`]));
        $(".textToggleDisplayButtonLabel.cancelButton").attr({
        });
            "data-style-off": parsedDataset.config["cancel@off"] || "",
    });
            "data-style-on": parsedDataset.config["cancel@on"] || "",
    triggerChangeHandler($(".textToggleDisplayButtonInput").on("change", ({
        });
        target,
        $(".textToggleDisplayButtonLabel.cancelButton > input").attr("style", cssSanitizer(parsedDataset.config["cancel@input"]));
    }, fromTriggerHandler = false) => {
        getEntries(parsedDataset.data).forEach(([id]) => {
        const {
            $(`.textToggleDisplayButtonLabel[data-id="${id}"]`).attr({
            dataset: {
                "data-style-off": parsedDataset.data[`${id}@off`] || "",
                id,
                "data-style-on": parsedDataset.data[`${id}@on`] || "",
            },
            }).children("input").attr("style", cssSanitizer(parsedDataset.data[`${id}@input`]));
            checked,
        });
        } = target;
    });
        const textToggleDisplayTarget = $(`.textToggleDisplay[data-id="${id}"]`);
    triggerChangeHandler($(".textToggleDisplayButtonInput").on("change", ({
        const { config: { toggleClass } } = datasetParser($(target).closest(".textToggleDisplayButtons")[0]);
        target,
        const toggleClassName = typeof toggleClass === "string" && toggleClass.length > 0 ? toggleClass : "hidden";
    }, fromTriggerHandler = false) => {
        if (toggleClassName !== "hidden") {
        const {
            textToggleDisplayTarget.removeClass("hidden");
            dataset: {
        }
                id,
        textToggleDisplayTarget[checked ? "removeClass" : "addClass"](toggleClassName)[checked ? "addClass" : "removeClass"]("textToggleDisplay-on");
            },
        textToggleDisplayTarget.prev(".textToggleDisplay")[checked ? "addClass" : "removeClass"]("textToggleDisplay-before-on");
            checked,
        textToggleDisplayTarget.next(".textToggleDisplay")[checked ? "addClass" : "removeClass"]("textToggleDisplay-after-on");
        } = target;
        const self = $(target);
        const textToggleDisplayTarget = $(`.textToggleDisplay[data-id="${id}"]`);
        const label = self.closest(".textToggleDisplayButtonLabel");
        const { config: { toggleClass } } = datasetParser($(target).closest(".textToggleDisplayButtons")[0]);
        const span = label.children(".on");
        const toggleClassName = typeof toggleClass === "string" && toggleClass.length > 0 ? toggleClass : "hidden";
        label[checked ? "addClass" : "removeClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-on" : "data-style-off")));
        if (toggleClassName !== "hidden") {
        if (checked) {
            textToggleDisplayTarget.removeClass("hidden");
            span.attr("style", cssSanitizer(textToggleDisplayStyle[id]));
        }
        } else {
        textToggleDisplayTarget[checked ? "removeClass" : "addClass"](toggleClassName)[checked ? "addClass" : "removeClass"]("textToggleDisplay-on");
            span.removeAttr("style");
        textToggleDisplayTarget.prev(".textToggleDisplay")[checked ? "addClass" : "removeClass"]("textToggleDisplay-before-on");
        }
        textToggleDisplayTarget.next(".textToggleDisplay")[checked ? "addClass" : "removeClass"]("textToggleDisplay-after-on");
        const labelContainer = label.closest("span[data-order][data-key]");
        const self = $(target);
        labelContainer.prev("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").last()[checked ? "addClass" : "removeClass"]("before-on");
        const label = self.closest(".textToggleDisplayButtonLabel");
        labelContainer.next("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").first()[checked ? "addClass" : "removeClass"]("after-on");
        const span = label.children(".on");
        if (!fromTriggerHandler) {
        label[checked ? "addClass" : "removeClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-on" : "data-style-off")));
            triggerChangeHandler(self.closest(".textToggleDisplayButtons").find("input").not(target));
        if (checked) {
        }
            span.attr("style", cssSanitizer(textToggleDisplayStyle[id]));
    }));
        } else {
    triggerChangeHandler($(".textToggleDisplayButtonInputReverse").on("change", ({
            span.removeAttr("style");
        target,
        }
    }, fromTriggerHandler = false) => {
        const labelContainer = label.closest("span[data-order][data-key]");
        const {
        labelContainer.prev("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").last()[checked ? "addClass" : "removeClass"]("before-on");
            dataset: {
        labelContainer.next("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").first()[checked ? "addClass" : "removeClass"]("after-on");
                id,
        if (!fromTriggerHandler) {
                radioCancel,
            triggerChangeHandler(self.closest(".textToggleDisplayButtons").find("input").not(target));
            },
        }
            checked,
    }));
        } = target;
    triggerChangeHandler($(".textToggleDisplayButtonInputReverse").on("change", ({
        const isRadioCancel = (radioCancel || "").length > 0;
        target,
        const self = $(target);
    }, fromTriggerHandler = false) => {
        const label = self.closest(".textToggleDisplayButtonLabel");
        const {
        if (isRadioCancel) {
            dataset: {
            label[checked ? "addClass" : "removeClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-on" : "data-style-off")));
                id,
        } else {
                radioCancel,
            const textToggleDisplayTarget = $(`.textToggleDisplay[data-id="${id}"]`);
            },
            const { config: { toggleClass } } = datasetParser($(target).closest(".textToggleDisplayButtons")[0]);
            checked,
            const toggleClassName = typeof toggleClass === "string" && toggleClass.length > 0 ? toggleClass : "hidden";
        } = target;
            if (toggleClassName !== "hidden") {
        const isRadioCancel = (radioCancel || "").length > 0;
                textToggleDisplayTarget.removeClass("hidden");
        const self = $(target);
            }
        const label = self.closest(".textToggleDisplayButtonLabel");
            textToggleDisplayTarget[checked ? "addClass" : "removeClass"](toggleClassName)[checked ? "removeClass" : "addClass"]("textToggleDisplay-on");
        if (isRadioCancel) {
            textToggleDisplayTarget.prev(".textToggleDisplay")[checked ? "removeClass" : "addClass"]("textToggleDisplay-before-on");
            label[checked ? "addClass" : "removeClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-on" : "data-style-off")));
            textToggleDisplayTarget.next(".textToggleDisplay")[checked ? "removeClass" : "addClass"]("textToggleDisplay-after-on");
        } else {
            const span = label.children("span");
            const textToggleDisplayTarget = $(`.textToggleDisplay[data-id="${id}"]`);
            label[checked ? "removeClass" : "addClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-off" : "data-style-on")));
            const { config: { toggleClass } } = datasetParser($(target).closest(".textToggleDisplayButtons")[0]);
            if (checked) {
            const toggleClassName = typeof toggleClass === "string" && toggleClass.length > 0 ? toggleClass : "hidden";
                span.removeAttr(".on");
            if (toggleClassName !== "hidden") {
            } else {
                textToggleDisplayTarget.removeClass("hidden");
                span.attr("style", cssSanitizer(textToggleDisplayStyle[id]));
            }
            }
            textToggleDisplayTarget[checked ? "addClass" : "removeClass"](toggleClassName)[checked ? "removeClass" : "addClass"]("textToggleDisplay-on");
        }
            textToggleDisplayTarget.prev(".textToggleDisplay")[checked ? "removeClass" : "addClass"]("textToggleDisplay-before-on");
        const labelContainer = label.closest("span[data-order][data-key]");
            textToggleDisplayTarget.next(".textToggleDisplay")[checked ? "removeClass" : "addClass"]("textToggleDisplay-after-on");
        labelContainer.prev("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").last()[checked ? "addClass" : "removeClass"]("before-on");
            const span = label.children("span");
        labelContainer.next("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").first()[checked ? "addClass" : "removeClass"]("after-on");
            label[checked ? "removeClass" : "addClass"]("on").attr("style", cssSanitizer(label.attr(checked ? "data-style-off" : "data-style-on")));
        if (!fromTriggerHandler) {
            if (checked) {
            triggerChangeHandler(self.closest(".textToggleDisplayButtons").find("input").not(target));
                span.removeAttr(".on");
        }
            } else {
    }));
                span.attr("style", cssSanitizer(textToggleDisplayStyle[id]));
    $(window).on("beforeunload", () => {
            }
        $(".textToggleDisplayButtons input[type=checkbox]").prop("checked", false);
        }
    });
        const labelContainer = label.closest("span[data-order][data-key]");
}
        labelContainer.prev("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").last()[checked ? "addClass" : "removeClass"]("before-on");
        labelContainer.next("span[data-order][data-key]").children(".textToggleDisplayButtonLabel").first()[checked ? "addClass" : "removeClass"]("after-on");
        if (!fromTriggerHandler) {
            triggerChangeHandler(self.closest(".textToggleDisplayButtons").find("input").not(target));
        }
    }));
    $(window).on("beforeunload", () => {
        $(".textToggleDisplayButtons input[type=checkbox]").prop("checked", false);
    });
}


///////结束////////
///////结束////////

导航菜单