MediaWiki:Gadget-VectorThemeLoader.js
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Internet Explorer或Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5
- Opera:按 Ctrl-F5。
"use strict";
(() => {
// src/utils/resource.ts
function addStyleUrl(url, key) {
let style;
if (key && document.getElementById(key) instanceof HTMLLinkElement) {
style = document.getElementById(key);
} else {
style = document.createElement("link");
style.rel = "stylesheet";
style.type = "text/css";
if (key)
style.id = key;
}
if (style.href === url)
return;
style.href = url;
document.head.appendChild(style);
}
function addStyle(css) {
const style = document.createElement("style");
style.textContent = css;
document.head.appendChild(style);
}
function loadWikiStyle(page, key) {
addStyleUrl(`https://mcbbs.wiki/index.php?title=${page}&action=raw&ctype=text/css`, key);
}
// src/utils/storage.ts
function parse(str) {
if (str) {
try {
return JSON.parse(str);
} catch (e) {
}
}
return null;
}
function write(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
function unsafeRead(key) {
const storage = localStorage.getItem(key);
return parse(storage);
}
function listen(listener, options = { passive: true }) {
window.addEventListener("storage", listener, options);
return () => window.removeEventListener("storage", listener, options);
}
function readAndListen(props) {
const {
key,
defaultValue,
listener,
callOnChange = true,
options = { passive: true }
} = props;
let v = unsafeRead(key);
if (defaultValue !== void 0 && v === null) {
write(key, defaultValue);
v = defaultValue;
}
const fn = (ev) => {
if (ev.key !== key || ev.storageArea !== localStorage)
return;
const newValue = parse(ev.newValue);
const oldValue = parse(ev.oldValue);
if (callOnChange && newValue === oldValue)
return;
const encapsulatedEvent = {
key,
newValue,
oldValue,
storageArea: ev.storageArea,
url: ev.url
};
listener(encapsulatedEvent);
};
const off = listen(fn, options);
return [v, off];
}
// src/utils/utils.ts
var i = document.createElement("textarea");
i.setAttribute("style", "pointer-events:none;opacity:0;position:fixed;");
function clickOutside(el, callback) {
const cb = (ev) => {
const { target } = ev;
if (!(target instanceof Element))
return;
if (target === el)
return;
let obj = target.parentElement;
while (obj && obj !== el && obj.parentElement) {
obj = obj.parentElement;
}
if (obj !== el)
callback();
};
window.addEventListener("click", cb, true);
return () => window.removeEventListener("click", cb);
}
// widget/VectorThemeLoader/SwitchPanel.ts
function createPanel(props, ...innerElements) {
const {
className,
position: { x, y }
} = props;
const panel = document.createElement("div");
panel.className = `salt-panel ${className || ""}`;
panel.style.position = "absolute";
for (const el of innerElements)
panel.appendChild(el);
document.body.appendChild(panel);
const { offsetWidth, offsetHeight } = panel;
panel.style.left = `${Math.max(x - offsetWidth / 2, 0)}px`;
panel.style.top = `${y + 2}px`;
const cancel = clickOutside(panel, () => {
console.log("awa");
panel.remove();
cancel();
});
return panel;
}
// widget/VectorThemeLoader/widget.t.scss
var widget_t_default = `
.salt-panel.style-list {
padding: 8px 12px;
border-radius: 4px;
background-color: var(--lightcolor, #f9f9f9);
box-shadow: 1px 2px 5px 0 rgba(153, 153, 153, 0.4);
font-size: 1rem;
z-index: 9999;
}
.salt-panel.style-list, .salt-panel.style-list * {
box-sizing: border-box;
}
.salt-panel.style-list .style-list-item {
display: block;
min-width: 196px;
margin: 4px 0;
list-style: none;
overflow: hidden;
}
.salt-panel.style-list .style-list-item .theme-list {
padding: 2px 4px;
margin: 0;
overflow: hidden;
}
.salt-panel.style-list .style-list-item .theme-list .theme-list-item {
padding: 4px 8px;
list-style: none;
overflow: hidden;
user-select: none;
cursor: pointer;
}
.salt-panel.style-list .style-list-item .theme-list .theme-list-item:hover {
background-color: rgba(153, 153, 153, 0.0666666667);
}
.salt-panel.style-list .style-list-item .theme-list .theme-list-item:active {
background-color: rgba(153, 153, 153, 0.2);
}
.salt-panel.style-list .style-list-item .theme-list .theme-list-item .theme-list-item-img {
display: inline-block;
width: 1rem;
height: 1rem;
vertical-align: middle;
margin-right: 4px;
}
.salt-panel.style-list .style-list-item .theme-list .theme-list-item .theme-list-item-name {
display: inline;
}`;
// widget/VectorThemeLoader/widget.ts
//! https://github.com/mcbbs-wiki/mcbbs-wiki-widget-repo/tree/master/widget/VectorThemeLoader
addStyle(widget_t_default);
var isLegacy = document.body.classList.contains("skin-vector-legacy");
var themeMap = isLegacy ? {
book: {
name: "仿MCBBS书页风格",
common: "MediaWiki:Vector-Legacy-Book.css",
default: {
name: "夏季主题",
css: "MediaWiki:Vector-Book-Summer.css",
img: "https://mcbbs.wiki/images/2/2f/艺术家与认证用户回帖图标.png"
},
other: {
nether: { name: "下界主题", css: "MediaWiki:Vector-Book-Nether.css" },
winter: { name: "冬季主题", css: "MediaWiki:Vector-Book-Winter.css" }
}
}
} : {
v4: {
name: "仿MCBBS v4风格",
common: "MediaWiki:Vector-V4.css",
default: { name: "默认风格", css: "MediaWiki:Vector-V4.css" },
other: {}
}
};
var defaultStyle = Object.keys(themeMap)[0];
var styleKey = isLegacy ? "mcbbs-wiki-skin-vector-legacy-style" : "mcbbs-wiki-skin-vector-style";
var themeKey = isLegacy ? "mcbbs-wiki-skin-vector-legacy-theme" : "mcbbs-wiki-skin-vector-theme";
var loadThemeStyle = (style, theme) => {
const styleMap = themeMap[style] || themeMap[defaultStyle];
const currentCommonStyle = styleMap.common;
loadWikiStyle(currentCommonStyle, "salt-wiki-style-common");
const currentTheme = theme === "default" || !styleMap.other[theme] ? styleMap.default : styleMap.other[theme];
loadWikiStyle(currentTheme.css, "salt-wiki-style-theme");
};
var initTheme = () => {
const current = { style: defaultStyle, theme: "default" };
const [style] = readAndListen({
key: styleKey,
defaultValue: defaultStyle,
listener: (ev) => {
if (ev.newValue) {
current.style = ev.newValue;
loadCurrentTheme();
}
}
});
const [theme] = readAndListen({
key: themeKey,
defaultValue: "default",
listener: (ev) => {
if (ev.newValue) {
current.theme = ev.newValue;
loadCurrentTheme();
}
}
});
current.style = style;
current.theme = theme;
const loadCurrentTheme = () => {
const { style: style2, theme: theme2 } = current;
loadThemeStyle(style2, theme2);
};
loadCurrentTheme();
};
initTheme();
var handleSwitchBtn = (ev) => {
const { top, left } = $(btn).offset();
console.log(ev);
const innerElements = [];
const createThemeSwitch = (style, themeCode, theme) => {
const { name, img: imgSrc } = theme;
const handleClick = () => {
write(styleKey, style);
write(themeKey, themeCode);
loadThemeStyle(style, themeCode);
};
const li2 = document.createElement("li");
li2.className = "theme-list-item";
li2.addEventListener("click", handleClick);
if (imgSrc) {
const img = document.createElement("img");
img.src = imgSrc;
img.className = "theme-list-item-img";
li2.appendChild(img);
}
const div = document.createElement("div");
div.textContent = name;
div.className = "theme-list-item-name";
li2.appendChild(div);
return li2;
};
for (const style in themeMap) {
const li2 = document.createElement("li");
li2.className = "style-list-item";
const title = document.createElement("div");
title.className = "style-list-item-title";
title.textContent = themeMap[style].name;
const ul = document.createElement("ul");
ul.className = "theme-list";
const themeList = [];
const defaultTheme = themeMap[style].default;
themeList.push(createThemeSwitch(style, "default", defaultTheme));
for (const themeCode in themeMap[style].other) {
themeList.push(createThemeSwitch(style, themeCode, themeMap[style].other[themeCode]));
}
for (const el of themeList)
ul.appendChild(el);
li2.appendChild(title);
li2.appendChild(ul);
innerElements.push(li2);
}
createPanel({
className: "style-list",
position: { x: left, y: top + btn.offsetHeight }
}, ...innerElements);
};
var headLogoutBtn = document.getElementById("pt-logout");
var btn = document.createElement("a");
btn.textContent = "切换主题";
btn.title = "切换主题";
btn.onclick = handleSwitchBtn;
var li = document.createElement("li");
li.className = "mw-list-item";
li.appendChild(btn);
console.log("headLogoutBtn.parentElement", headLogoutBtn.parentElement);
headLogoutBtn.parentElement.insertBefore(li, headLogoutBtn);
})();