MediaWiki:Gadget-FloatTOC.js
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
/**
* SPDX-License-Identifier: GPL-3.0-or-later
* _addText: '{{Gadget Header|license=GPL-3.0-or-later}}'
*
* @source {@link https://git.qiuwen.net.cn/InterfaceAdmin/QiuwenGadgets/src/branch/master/src/FloatTOC}
* @author 安忆 <i@anyi.in>
* @license GPL-3.0-or-later {@link https://www.qiuwenbaike.cn/wiki/H:GPL-3.0}
*/
/**
* Copyright (C) 安忆
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* +------------------------------------------------------------+
* | === WARNING: GLOBAL GADGET FILE === |
* +------------------------------------------------------------+
* | All changes should be made in the repository, |
* | otherwise they will be lost. |
* +------------------------------------------------------------+
* | Changes to this page may affect many users. |
* | Please discuss changes by opening an issue before editing. |
* +------------------------------------------------------------+
*/
/* <nowiki> */
(() => {
"use strict";
// dist/FloatTOC/FloatTOC.js
//! src/FloatTOC/options.json
var elementId = "floatTOC";
//! src/FloatTOC/modules/core.ts
var import_ext_gadget2 = require("ext.gadget.Util");
var import_ext_gadget3 = require("ext.gadget.FilterAlteredClicks");
//! src/FloatTOC/modules/i18n.ts
var getI18nMessages = () => {
return {
Close: {
"zh-hans": "关闭",
"zh-hant": "關閉",
en: "Close"
},
Contents: {
"zh-hans": "目录",
"zh-hant": "目錄",
en: "Contents"
},
Collapse: {
"zh-hans": "折叠",
"zh-hant": "摺疊",
en: "Collapse"
},
Expand: {
"zh-hans": "展开",
"zh-hant": "展開",
en: "Expand"
}
};
};
var i18nMessages = getI18nMessages();
var getMessage = (key) => {
var lang = mw.config.get("wgUserLanguage");
var msgs = i18nMessages[key];
if (!msgs) {
return key;
}
return msgs[lang] || msgs["zh-hans"] || key;
};
//! src/FloatTOC/modules/util/generateElements.ts
var generateElements = (originToc) => {
var _toc$querySelector, _toc$querySelector2;
const toc = originToc.cloneNode(true);
(_toc$querySelector = toc.querySelector("input")) === null || _toc$querySelector === void 0 || _toc$querySelector.remove();
(_toc$querySelector2 = toc.querySelector(".toctogglespan")) === null || _toc$querySelector2 === void 0 || _toc$querySelector2.remove();
const $toc = $(toc);
const $floatToc = $toc.clone().removeAttr("id").prepend($("<span>").addClass("oo-ui-indicatorElement-indicator oo-ui-icon-close").attr({
id: "close",
title: getMessage("Close"),
role: "button",
tabindex: "0"
}));
const $floatTocOpener = $("<div>").addClass("noprint").attr({
id: "floatToc-opener",
title: getMessage("Contents"),
role: "button",
tabindex: "0"
}).append($("<span>").addClass("oo-ui-indicatorElement-indicator oo-ui-icon-reference"), $("<span>").text(getMessage("Contents")));
return {
$floatToc,
$floatTocOpener
};
};
//! src/FloatTOC/modules/util/generateTogglerElement.ts
var generateTogglerElement = (isCollapse) => {
let $toggler = $("<span>").addClass("oo-ui-indicatorElement-indicator oo-ui-icon-downTriangle");
$toggler = isCollapse ? $toggler.attr("title", getMessage("Expand")) : $toggler.attr("title", getMessage("Collapse")).addClass("collapse");
return $toggler;
};
//! src/FloatTOC/modules/getConfig.ts
var getConfig = (id) => {
let config = mw.storage.getObject(id);
config || (config = {
floatTOC: window.outerHeight < window.outerWidth ? "open" : "close",
originTOC: "open"
});
return config;
};
//! src/FloatTOC/modules/setMwNotifyStyle.ts
var setMwNotifyStyle = () => {
const style = mw.loader.addStyleTag(".mw-notification-area{right:unset;width:auto;max-width:20em}.mw-notification{transform:translateX(-999px)}.mw-notification-visible{transform:translateX(0)}");
style.disabled = true;
return style;
};
//! src/FloatTOC/modules/core.ts
var floatTOC = ($originToc) => {
const {
skin
} = mw.config.get();
const originToc = $originToc.get(0);
const $body = $originToc.parents("body");
const {
$floatToc,
$floatTocOpener
} = generateElements(originToc);
$floatTocOpener.hide().appendTo($body);
const config = getConfig(elementId);
const mwNotifyStyle = setMwNotifyStyle();
let isShow = false;
const storeState = (target, state) => {
config[target] = state;
mw.storage.setObject(elementId, config);
};
let disableMwNotifyStyleTimer;
const disableMwNotifyStyle = () => {
if (disableMwNotifyStyleTimer) {
clearTimeout(disableMwNotifyStyleTimer);
}
disableMwNotifyStyleTimer = setTimeout(() => {
if (!isShow) {
mwNotifyStyle.disabled = true;
}
}, 5 * 1e3);
};
let notification;
const closeNotification = (currentNotification) => {
currentNotification.close();
$floatTocOpener.fadeIn();
storeState("floatTOC", "close");
disableMwNotifyStyle();
};
const smoothScroll = (event) => {
if (skin === "citizen") {
return;
}
const target = event.target;
const $target = $(target).parent();
const href = $target.attr("href");
if (!href) {
return;
}
const anchorOffset = $(href).offset();
if (!anchorOffset) {
return;
}
event.preventDefault();
(0, import_ext_gadget2.scrollTop)("".concat(anchorOffset.top, "px"));
};
const toggleToc = (currentIsShow = true, preNotification = void 0) => {
var _preNotification;
(_preNotification = preNotification) === null || _preNotification === void 0 || _preNotification.close();
isShow = !!currentIsShow;
switch (currentIsShow) {
case true:
if (config.floatTOC === "close") {
$floatTocOpener.fadeIn();
return;
}
break;
case "open":
$floatTocOpener.fadeOut();
storeState("floatTOC", "open");
break;
default:
$floatTocOpener.fadeOut();
disableMwNotifyStyle();
return;
}
mwNotifyStyle.disabled = false;
if (preNotification) {
preNotification.start();
} else {
preNotification = mw.notification.notify($floatToc, {
classes: "noprint",
id: elementId,
autoHide: false
});
const notificationListener = (event) => {
event.stopPropagation();
if (!(0, import_ext_gadget2.checkA11yConfirmKey)(event)) {
return;
}
const target = event.target;
if (target.id === "close") {
closeNotification(preNotification);
} else {
smoothScroll(event);
}
};
preNotification.$notification.on("click", (0, import_ext_gadget3.filterAlteredClicks)((event) => {
void notificationListener(event);
}));
preNotification.$notification.on("keydown", notificationListener);
}
return preNotification;
};
const observerCallback = (entries) => {
const [entry] = entries;
if (!entry) {
return;
}
const {
intersectionRatio
} = entry;
notification = toggleToc(intersectionRatio === 0, notification);
};
const intersectionObserver = new IntersectionObserver(observerCallback);
intersectionObserver.observe(originToc);
const openerListener = (event) => {
event.preventDefault();
if (!(0, import_ext_gadget2.checkA11yConfirmKey)(event)) {
return;
}
notification = toggleToc("open");
};
$floatTocOpener.on("click", openerListener);
$floatTocOpener.on("keydown", openerListener);
const collapseOriginToc = () => {
if (skin !== "citizen") {
return;
}
const isCollapse = config.originTOC === "close";
const $originTocTitle = $body.find("#toc .toctitle");
const $originTocItem = $body.find("#toc ul");
const $toggler = generateTogglerElement(isCollapse);
$originTocTitle.append($toggler);
const collapseToggle = () => {
const $element = $originTocTitle.find(".oo-ui-indicatorElement-indicator");
$element.toggleClass("collapse");
if (isCollapse) {
$element.attr("title", getMessage("Expand"));
} else {
$element.attr("title", getMessage("Collapse"));
}
};
$originTocTitle.on("click", () => {
storeState("originTOC", isCollapse ? "open" : "close");
collapseToggle();
$originTocItem.fadeToggle();
});
if (isCollapse) {
$originTocItem.fadeOut();
}
};
collapseOriginToc();
};
//! src/FloatTOC/FloatTOC.ts
var import_ext_gadget4 = require("ext.gadget.Util");
void (0, import_ext_gadget4.getBody)().then(($body) => {
const $originToc = $body.find("#toc");
if (!$originToc.length) {
return;
}
floatTOC($originToc);
});
})();
/* </nowiki> */