mirror of
https://gitee.com/butubb8/blowfish.git
synced 2025-12-05 14:17:50 +08:00
refactor(a11y): simply code
This commit is contained in:
@@ -1,194 +1,168 @@
|
||||
const getA11ySettings = () => {
|
||||
const settings = localStorage.getItem("a11ySettings");
|
||||
return settings
|
||||
? JSON.parse(settings)
|
||||
: {
|
||||
disableBlur: false,
|
||||
disableImages: false,
|
||||
fontSize: "default",
|
||||
underlineLinks: false,
|
||||
zenMode: false,
|
||||
};
|
||||
};
|
||||
window.A11yPanel = (() => {
|
||||
const FEATURES = {
|
||||
disableBlur: {
|
||||
default: false,
|
||||
apply: (enabled) => {
|
||||
document.querySelectorAll("script[data-target-id]").forEach((script) => {
|
||||
const targetId = script.getAttribute("data-target-id");
|
||||
const scrollDivisor = Number(script.getAttribute("data-scroll-divisor") || 300);
|
||||
if (typeof setBackgroundBlur === "function") {
|
||||
setBackgroundBlur(targetId, scrollDivisor, enabled, targetId === "menu-blur");
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
const saveA11ySettings = (settings) => {
|
||||
localStorage.setItem("a11ySettings", JSON.stringify(settings));
|
||||
};
|
||||
disableImages: {
|
||||
default: false,
|
||||
apply: (enabled) => {
|
||||
document.querySelectorAll("script[data-target-id]").forEach((script) => {
|
||||
const image = document.getElementById(script.getAttribute("data-image-id"));
|
||||
const imageUrl = script.getAttribute("data-image-url");
|
||||
if (image) {
|
||||
image.style.display = enabled ? "none" : "";
|
||||
if (!enabled && imageUrl && !image.src) image.src = imageUrl;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
const applyImageState = (imageElement, imageUrl, disableImages) => {
|
||||
if (!imageElement) return;
|
||||
if (disableImages) {
|
||||
imageElement.style.display = "none";
|
||||
} else {
|
||||
imageElement.style.display = "";
|
||||
if (imageUrl && !imageElement.getAttribute("src")) {
|
||||
imageElement.setAttribute("src", imageUrl);
|
||||
fontSize: {
|
||||
default: "default",
|
||||
apply: (size) => {
|
||||
document.documentElement.style.fontSize = size === "default" ? "" : size;
|
||||
},
|
||||
},
|
||||
|
||||
underlineLinks: {
|
||||
default: false,
|
||||
apply: (enabled) => {
|
||||
const existing = document.getElementById("a11y-underline-links");
|
||||
if (enabled && !existing) {
|
||||
const style = document.createElement("style");
|
||||
style.id = "a11y-underline-links";
|
||||
style.textContent = "a { text-decoration: underline !important; }";
|
||||
document.head.appendChild(style);
|
||||
} else if (!enabled && existing) {
|
||||
existing.remove();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
zenMode: {
|
||||
default: false,
|
||||
apply: (enabled) => {
|
||||
const isActive = document.body?.classList.contains("zen-mode-enable");
|
||||
if (enabled !== isActive) {
|
||||
const checkbox = document.querySelector('[id$="zen-mode"]');
|
||||
if (checkbox && typeof _toggleZenMode === "function") {
|
||||
_toggleZenMode(checkbox, { scrollToHeader: false });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let settings = null;
|
||||
|
||||
const getSettings = () => {
|
||||
if (settings) return settings;
|
||||
const defaults = Object.fromEntries(Object.entries(FEATURES).map(([key, config]) => [key, config.default]));
|
||||
try {
|
||||
const saved = localStorage.getItem("a11ySettings");
|
||||
settings = { ...defaults, ...JSON.parse(saved || "{}") };
|
||||
} catch {
|
||||
settings = defaults;
|
||||
}
|
||||
}
|
||||
};
|
||||
return settings;
|
||||
};
|
||||
|
||||
const applyFontSize = (fontSizePx) => {
|
||||
const isDefaultSettings = localStorage.getItem("a11ySettings") === null;
|
||||
if (!isDefaultSettings && fontSizePx !== "default") {
|
||||
document.documentElement.style.fontSize = fontSizePx;
|
||||
}
|
||||
};
|
||||
|
||||
const applyUnderlineLinks = (enabled) => {
|
||||
let styleElement = document.getElementById("a11y-underline-links");
|
||||
if (enabled) {
|
||||
if (!styleElement) {
|
||||
styleElement = document.createElement("style");
|
||||
styleElement.id = "a11y-underline-links";
|
||||
styleElement.textContent = "a { text-decoration: underline !important; }";
|
||||
document.head.appendChild(styleElement);
|
||||
const updateSetting = (key, value) => {
|
||||
const current = getSettings();
|
||||
current[key] = value;
|
||||
try {
|
||||
localStorage.setItem("a11ySettings", JSON.stringify(current));
|
||||
} catch (e) {
|
||||
console.warn(`a11y.js: can not store settings: ${e}`);
|
||||
}
|
||||
} else {
|
||||
if (styleElement) {
|
||||
styleElement.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
FEATURES[key]?.apply(value);
|
||||
};
|
||||
|
||||
const applyZenMode = (enabled) => {
|
||||
const body = document.querySelector("body");
|
||||
const isZenModeActive = body && body.classList.contains("zen-mode-enable");
|
||||
const initPanel = (panelId) => {
|
||||
const prefix = panelId.replace("a11y-panel", "");
|
||||
const current = getSettings();
|
||||
|
||||
// Toggle only if current state doesn't match desired state
|
||||
if (enabled !== isZenModeActive) {
|
||||
const zenModeCheckbox = document.querySelector('[id$="zen-mode"]');
|
||||
if (zenModeCheckbox && typeof _toggleZenMode === "function") {
|
||||
_toggleZenMode(zenModeCheckbox, { scrollToHeader: false });
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.entries(FEATURES).forEach(([key, config]) => {
|
||||
const elementId = `${prefix}${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
|
||||
const element = document.getElementById(elementId) || document.getElementById(`${elementId}-select`);
|
||||
|
||||
const applyA11ySettings = () => {
|
||||
const settings = getA11ySettings();
|
||||
document.querySelectorAll("script[data-target-id]").forEach((script) => {
|
||||
const targetId = script.getAttribute("data-target-id");
|
||||
const scrollDivisor = Number(script.getAttribute("data-scroll-divisor") || 300);
|
||||
const imageId = script.getAttribute("data-image-id");
|
||||
const imageUrl = script.getAttribute("data-image-url");
|
||||
const isMenuBlur = targetId === "menu-blur";
|
||||
setBackgroundBlur(targetId, scrollDivisor, settings.disableBlur, isMenuBlur);
|
||||
applyImageState(document.getElementById(imageId), imageUrl, settings.disableImages);
|
||||
});
|
||||
applyFontSize(settings.fontSize);
|
||||
applyUnderlineLinks(settings.underlineLinks);
|
||||
applyZenMode(settings.zenMode);
|
||||
};
|
||||
|
||||
const updateA11ySetting = (key, value) => {
|
||||
const settings = getA11ySettings();
|
||||
settings[key] = value;
|
||||
saveA11ySettings(settings);
|
||||
applyA11ySettings();
|
||||
};
|
||||
|
||||
const toggleA11yPanel = (prefix = "") => {
|
||||
const panel = document.getElementById(`${prefix}a11y-panel`);
|
||||
const overlay = document.getElementById(`${prefix}a11y-overlay`);
|
||||
const button = document.getElementById(`${prefix}a11y-toggle`);
|
||||
if (!panel || !overlay || !button) return;
|
||||
if (overlay.classList.contains("hidden")) {
|
||||
overlay.classList.remove("hidden");
|
||||
panel.classList.remove("hidden");
|
||||
button.setAttribute("aria-pressed", "true");
|
||||
button.setAttribute("aria-expanded", "true");
|
||||
} else {
|
||||
overlay.classList.add("hidden");
|
||||
panel.classList.add("hidden");
|
||||
button.setAttribute("aria-pressed", "false");
|
||||
button.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
};
|
||||
|
||||
const initA11yPanel = (prefix = "") => {
|
||||
const settings = getA11ySettings();
|
||||
const checkboxBlur = document.getElementById(`${prefix}disable-blur`);
|
||||
const checkboxImages = document.getElementById(`${prefix}disable-images`);
|
||||
const checkboxUnderline = document.getElementById(`${prefix}underline-links`);
|
||||
const checkboxZenMode = document.getElementById(`${prefix}zen-mode`);
|
||||
const fontSizeSelect = document.getElementById(`${prefix}font-size-select`);
|
||||
const toggleButton = document.getElementById(`${prefix}a11y-toggle`);
|
||||
const closeButton = document.getElementById(`${prefix}a11y-close`);
|
||||
const overlay = document.getElementById(`${prefix}a11y-overlay`);
|
||||
|
||||
if (
|
||||
!checkboxBlur ||
|
||||
!checkboxImages ||
|
||||
!checkboxUnderline ||
|
||||
!checkboxZenMode ||
|
||||
!fontSizeSelect ||
|
||||
!toggleButton ||
|
||||
!closeButton ||
|
||||
!overlay
|
||||
) {
|
||||
console.warn(`One or more a11y elements not found for prefix: ${prefix}`);
|
||||
return;
|
||||
}
|
||||
|
||||
checkboxBlur.checked = settings.disableBlur;
|
||||
checkboxImages.checked = settings.disableImages;
|
||||
checkboxUnderline.checked = settings.underlineLinks;
|
||||
checkboxZenMode.checked = settings.zenMode;
|
||||
fontSizeSelect.value = settings.fontSize;
|
||||
|
||||
checkboxBlur.addEventListener("change", (e) => updateA11ySetting("disableBlur", e.target.checked));
|
||||
checkboxImages.addEventListener("change", (e) => updateA11ySetting("disableImages", e.target.checked));
|
||||
checkboxUnderline.addEventListener("change", (e) => updateA11ySetting("underlineLinks", e.target.checked));
|
||||
checkboxZenMode.addEventListener("change", (e) => {
|
||||
// Only save setting, let applyZenMode handle the toggle logic
|
||||
updateA11ySetting("zenMode", e.target.checked);
|
||||
});
|
||||
fontSizeSelect.addEventListener("change", (e) => {
|
||||
// Remove fontSize from localStorage when default is selected
|
||||
if (e.target.value === "default") {
|
||||
const settings = getA11ySettings();
|
||||
delete settings.fontSize;
|
||||
saveA11ySettings(settings);
|
||||
document.documentElement.style.fontSize = "";
|
||||
} else {
|
||||
updateA11ySetting("fontSize", e.target.value);
|
||||
}
|
||||
});
|
||||
|
||||
toggleButton.addEventListener("click", () => toggleA11yPanel(prefix));
|
||||
closeButton.addEventListener("click", () => toggleA11yPanel(prefix));
|
||||
overlay.addEventListener("click", (e) => {
|
||||
if (e.target === overlay) {
|
||||
toggleA11yPanel(prefix);
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll(`.ios-toggle${prefix ? `[id^="${prefix}"]` : ""}`).forEach((toggle) => {
|
||||
const checkbox = toggle.querySelector('input[type="checkbox"]');
|
||||
if (!checkbox) return;
|
||||
const newToggle = toggle.cloneNode(true);
|
||||
toggle.parentNode.replaceChild(newToggle, toggle);
|
||||
newToggle.addEventListener("click", () => {
|
||||
const newCheckbox = newToggle.querySelector('input[type="checkbox"]');
|
||||
if (newCheckbox) {
|
||||
newCheckbox.checked = !newCheckbox.checked;
|
||||
newCheckbox.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
if (element) {
|
||||
if (element.type === "checkbox") {
|
||||
element.checked = current[key];
|
||||
element.onchange = (e) => updateSetting(key, e.target.checked);
|
||||
} else if (element.tagName === "SELECT") {
|
||||
element.value = current[key];
|
||||
element.onchange = (e) => updateSetting(key, e.target.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
document.querySelectorAll("script[data-target-id]").forEach((script) => {
|
||||
const imageId = script.getAttribute("data-image-id");
|
||||
const imageUrl = script.getAttribute("data-image-url");
|
||||
const settings = getA11ySettings();
|
||||
applyImageState(document.getElementById(imageId), imageUrl, settings.disableImages);
|
||||
});
|
||||
const togglePanel = () => {
|
||||
const panel = document.getElementById(panelId);
|
||||
const overlay = document.getElementById(`${prefix}a11y-overlay`);
|
||||
const toggle = document.getElementById(`${prefix}a11y-toggle`);
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
applyA11ySettings();
|
||||
const allPanels = document.querySelectorAll('[id$="a11y-panel"]');
|
||||
allPanels.forEach((panel) => {
|
||||
const prefix = panel.id.replace("a11y-panel", "");
|
||||
initA11yPanel(prefix);
|
||||
});
|
||||
});
|
||||
if (!panel || !overlay) return;
|
||||
|
||||
const isHidden = overlay.classList.contains("hidden");
|
||||
overlay.classList.toggle("hidden");
|
||||
panel.classList.toggle("hidden");
|
||||
|
||||
if (toggle) {
|
||||
toggle.setAttribute("aria-pressed", String(isHidden));
|
||||
toggle.setAttribute("aria-expanded", String(isHidden));
|
||||
}
|
||||
};
|
||||
|
||||
const toggle = document.getElementById(`${prefix}a11y-toggle`);
|
||||
const close = document.getElementById(`${prefix}a11y-close`);
|
||||
const overlay = document.getElementById(`${prefix}a11y-overlay`);
|
||||
|
||||
if (toggle) toggle.onclick = togglePanel;
|
||||
if (close) close.onclick = togglePanel;
|
||||
if (overlay) overlay.onclick = (e) => e.target === overlay && togglePanel();
|
||||
};
|
||||
|
||||
const applyAll = () => {
|
||||
const current = getSettings();
|
||||
Object.entries(current).forEach(([key, value]) => {
|
||||
FEATURES[key]?.apply(value);
|
||||
});
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
applyAll();
|
||||
document.querySelectorAll('[id$="a11y-panel"]').forEach((panel) => {
|
||||
initPanel(panel.id);
|
||||
});
|
||||
};
|
||||
|
||||
if (getSettings().disableImages) {
|
||||
FEATURES.disableImages.apply(true);
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
return {
|
||||
getSettings,
|
||||
updateSetting,
|
||||
addFeature: (name, config) => {
|
||||
FEATURES[name] = config;
|
||||
FEATURES[name].apply(getSettings()[name] || config.default);
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user