您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
密码输入框内容可聚焦即显 / 悬浮即览 / 双击切换 / 始终可见 | 通过菜单或快捷键(Meta/Ctrl+Alt+P)切换显示模式
- // ==UserScript==
- // @name Password Revealer
- // @name:zh-CN 密码显示助手
- // @name:zh-TW 密碼顯示助手
- // @description Password Field Content Via - Reveal On Focus / Preview On Hover / Toggle On Double-Click / Always Visible | Switch Display Mode Via Menu Or Shortcut (Meta/Ctrl+Alt+P)
- // @description:zh-CN 密码输入框内容可聚焦即显 / 悬浮即览 / 双击切换 / 始终可见 | 通过菜单或快捷键(Meta/Ctrl+Alt+P)切换显示模式
- // @description:zh-TW 密碼輸入框內容可聚焦即顯 / 懸停即覽 / 雙擊切換 / 始終可見 | 透過選單或快速鍵(Meta/Ctrl+Alt+P)切換顯示模式
- // @version 1.5.0
- // @icon https://raw.githubusercontent.com/MiPoNianYou/UserScripts/main/Icons/Password-Revealer-Icon.svg
- // @author 念柚
- // @namespace https://github.com/MiPoNianYou/UserScripts
- // @supportURL https://github.com/MiPoNianYou/UserScripts/issues
- // @license GPL-3.0
- // @match *://*/*
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant GM_unregisterMenuCommand
- // @grant GM_addStyle
- // @run-at document-idle
- // ==/UserScript==
- (function () {
- "use strict";
- const Config = {
- SCRIPT_SETTINGS: {
- UI_FONT_STACK: "-apple-system, BlinkMacSystemFont, system-ui, sans-serif",
- ANIMATION_DURATION_MS: 300,
- NOTIFICATION_VISIBILITY_DURATION_MS: 2000,
- },
- MODES: {
- FOCUS: "Focus",
- HOVER: "Hover",
- DBLCLICK: "DoubleClick",
- ALWAYS_SHOW: "AlwaysShow",
- },
- get VALID_MODES() {
- return [
- this.MODES.FOCUS,
- this.MODES.HOVER,
- this.MODES.DBLCLICK,
- this.MODES.ALWAYS_SHOW,
- ];
- },
- ELEMENT_IDS: {
- MODE_NOTIFICATION: "PasswordRevealerModeNotification",
- },
- CSS_CLASSES: {
- MODE_NOTIFICATION_VISIBLE: "pr-mode-notification--visible",
- BREATHING_DOT: "pr-breathing-dot",
- MODE_NOTIFICATION_MESSAGE: "pr-mode-notification-message",
- },
- ATTRIBUTES: {
- PROCESSED: "data-password-revealer-processed",
- },
- UI_TEXTS: {
- "zh-CN": {
- SCRIPT_TITLE: "密码显示助手",
- MENU_CMD_FOCUS: "「聚焦即显」模式",
- MENU_CMD_HOVER: "「悬浮即览」模式",
- MENU_CMD_DBLCLICK: "「双击切换」模式",
- MENU_CMD_ALWAYS_SHOW: "「始终可见」模式",
- ALERT_MSG_FOCUS: "模式已切换为「聚焦即显」",
- ALERT_MSG_HOVER: "模式已切换为「悬浮即览」",
- ALERT_MSG_DBLCLICK: "模式已切换为「双击切换」",
- ALERT_MSG_ALWAYS_SHOW: "模式已切换为「始终可见」",
- },
- "zh-TW": {
- SCRIPT_TITLE: "密碼顯示助手",
- MENU_CMD_FOCUS: "「聚焦即顯」模式",
- MENU_CMD_HOVER: "「懸停即覽」模式",
- MENU_CMD_DBLCLICK: "「雙擊切換」模式",
- MENU_CMD_ALWAYS_SHOW: "「始終可見」模式",
- ALERT_MSG_FOCUS: "模式已切換為「聚焦即顯」",
- ALERT_MSG_HOVER: "模式已切換為「懸停即覽」",
- ALERT_MSG_DBLCLICK: "模式已切換為「雙擊切換」",
- ALERT_MSG_ALWAYS_SHOW: "模式已切換為「始終可見」",
- },
- "en-US": {
- SCRIPT_TITLE: "Password Revealer",
- MENU_CMD_FOCUS: "「Reveal On Focus」Mode",
- MENU_CMD_HOVER: "「Preview On Hover」Mode",
- MENU_CMD_DBLCLICK: "「Toggle On Double-Click」Mode",
- MENU_CMD_ALWAYS_SHOW: "「Always Visible」Mode",
- ALERT_MSG_FOCUS: "Mode Switched To 「Reveal On Focus」",
- ALERT_MSG_HOVER: "Mode Switched To 「Preview On Hover」",
- ALERT_MSG_DBLCLICK: "Mode Switched To 「Toggle On Double-Click」",
- ALERT_MSG_ALWAYS_SHOW: "Mode Switched To 「Always Visible」",
- },
- },
- MODE_TO_MENU_TEXT_KEY_MAP: {
- ["Focus"]: "MENU_CMD_FOCUS",
- ["Hover"]: "MENU_CMD_HOVER",
- ["DoubleClick"]: "MENU_CMD_DBLCLICK",
- ["AlwaysShow"]: "MENU_CMD_ALWAYS_SHOW",
- },
- STORAGE_KEYS: {
- MODE_KEY: "PasswordDisplayMode",
- },
- MODE_TO_ALERT_MESSAGE_KEY_MAP: {
- ["Focus"]: "ALERT_MSG_FOCUS",
- ["Hover"]: "ALERT_MSG_HOVER",
- ["DoubleClick"]: "ALERT_MSG_DBLCLICK",
- ["AlwaysShow"]: "ALERT_MSG_ALWAYS_SHOW",
- },
- };
- const State = {
- currentMode: Config.MODES.FOCUS,
- currentLocale: "en-US",
- localizedStrings: Config.UI_TEXTS["en-US"],
- loadAndSetInitialState() {
- this.currentLocale = this.detectUserLanguage();
- this.localizedStrings =
- Config.UI_TEXTS[this.currentLocale] || Config.UI_TEXTS["en-US"];
- this.loadDisplayMode();
- },
- detectUserLanguage() {
- const languages = navigator.languages || [navigator.language];
- for (const lang of languages) {
- const langLower = lang.toLowerCase();
- if (langLower === "zh-cn") return "zh-CN";
- if (
- langLower === "zh-tw" ||
- langLower === "zh-hk" ||
- langLower === "zh-mo" ||
- langLower === "zh-hant"
- )
- return "zh-TW";
- if (langLower === "en-us") return "en-US";
- if (langLower.startsWith("zh-")) return "zh-CN";
- if (langLower.startsWith("en-")) return "en-US";
- }
- for (const lang of languages) {
- const langLower = lang.toLowerCase();
- if (langLower.startsWith("zh")) return "zh-CN";
- if (langLower.startsWith("en")) return "en-US";
- }
- return "en-US";
- },
- getLocalizedString(key, fallbackLang = "en-US") {
- const primaryLangData =
- this.localizedStrings || Config.UI_TEXTS[fallbackLang];
- const fallbackLangData = Config.UI_TEXTS[fallbackLang];
- return primaryLangData[key] ?? fallbackLangData[key] ?? `${key}?`;
- },
- loadDisplayMode() {
- let storedValue;
- try {
- storedValue = GM_getValue(
- Config.STORAGE_KEYS.MODE_KEY,
- Config.MODES.FOCUS
- );
- } catch (e) {
- storedValue = Config.MODES.FOCUS;
- }
- if (!Config.VALID_MODES.includes(storedValue)) {
- storedValue = Config.MODES.FOCUS;
- }
- this.currentMode = storedValue;
- },
- saveDisplayMode() {
- try {
- GM_setValue(Config.STORAGE_KEYS.MODE_KEY, this.currentMode);
- } catch (e) {}
- },
- setMode(newMode) {
- if (
- this.currentMode === newMode ||
- !Config.VALID_MODES.includes(newMode)
- ) {
- return false;
- }
- this.currentMode = newMode;
- this.saveDisplayMode();
- return true;
- },
- };
- const UserInterface = {
- notificationTimer: null,
- notificationRemovalTimer: null,
- registeredMenuCommandIds: [],
- injectCoreStyles() {
- const easeOutQuint = "cubic-bezier(0.23, 1, 0.32, 1)";
- const animationDuration = Config.SCRIPT_SETTINGS.ANIMATION_DURATION_MS;
- const baseCSS = `
- :root {
- --ctp-frappe-rosewater: rgb(242, 213, 207);
- --ctp-frappe-flamingo: rgb(238, 190, 190);
- --ctp-frappe-pink: rgb(244, 184, 228);
- --ctp-frappe-mauve: rgb(202, 158, 230);
- --ctp-frappe-red: rgb(231, 130, 132);
- --ctp-frappe-maroon: rgb(234, 153, 156);
- --ctp-frappe-peach: rgb(239, 159, 118);
- --ctp-frappe-yellow: rgb(229, 200, 144);
- --ctp-frappe-green: rgb(166, 209, 137);
- --ctp-frappe-teal: rgb(129, 200, 190);
- --ctp-frappe-sky: rgb(153, 209, 219);
- --ctp-frappe-sapphire: rgb(133, 193, 220);
- --ctp-frappe-blue: rgb(140, 170, 238);
- --ctp-frappe-lavender: rgb(186, 187, 241);
- --ctp-frappe-text: rgb(198, 208, 245);
- --ctp-frappe-subtext1: rgb(181, 191, 226);
- --ctp-frappe-subtext0: rgb(165, 173, 206);
- --ctp-frappe-overlay2: rgb(148, 156, 187);
- --ctp-frappe-overlay1: rgb(131, 139, 167);
- --ctp-frappe-overlay0: rgb(115, 121, 148);
- --ctp-frappe-surface2: rgb(98, 104, 128);
- --ctp-frappe-surface1: rgb(81, 87, 109);
- --ctp-frappe-surface0: rgb(65, 69, 89);
- --ctp-frappe-base: rgb(48, 52, 70);
- --ctp-frappe-mantle: rgb(41, 44, 60);
- --ctp-frappe-crust: rgb(35, 38, 52);
- --ctp-latte-rosewater: rgb(220, 138, 120);
- --ctp-latte-flamingo: rgb(221, 120, 120);
- --ctp-latte-pink: rgb(234, 118, 203);
- --ctp-latte-mauve: rgb(136, 57, 239);
- --ctp-latte-red: rgb(210, 15, 57);
- --ctp-latte-maroon: rgb(230, 69, 83);
- --ctp-latte-peach: rgb(254, 100, 11);
- --ctp-latte-yellow: rgb(223, 142, 29);
- --ctp-latte-green: rgb(64, 160, 43);
- --ctp-latte-teal: rgb(23, 146, 153);
- --ctp-latte-sky: rgb(4, 165, 229);
- --ctp-latte-sapphire: rgb(32, 159, 181);
- --ctp-latte-blue: rgb(30, 102, 245);
- --ctp-latte-lavender: rgb(114, 135, 253);
- --ctp-latte-text: rgb(76, 79, 105);
- --ctp-latte-subtext1: rgb(92, 95, 119);
- --ctp-latte-subtext0: rgb(108, 111, 133);
- --ctp-latte-overlay2: rgb(124, 127, 147);
- --ctp-latte-overlay1: rgb(140, 143, 161);
- --ctp-latte-overlay0: rgb(156, 160, 176);
- --ctp-latte-surface2: rgb(172, 176, 190);
- --ctp-latte-surface1: rgb(188, 192, 204);
- --ctp-latte-surface0: rgb(204, 208, 218);
- --ctp-latte-base: rgb(239, 241, 245);
- --ctp-latte-mantle: rgb(230, 233, 239);
- --ctp-latte-crust: rgb(220, 224, 232);
- --pr-notify-bg-dark: rgb(from var(--ctp-frappe-base) r g b / 0.85);
- --pr-notify-text-dark: var(--ctp-frappe-text);
- --pr-notify-border-dark: rgb(from var(--ctp-frappe-surface2) r g b / 0.25);
- --pr-notify-dot-color-dark: var(--ctp-frappe-green); /* Renamed from --ctp-frappe-green for clarity */
- --pr-notify-dot-glow-dark: rgb(from var(--ctp-frappe-green) r g b / 0.35); /* Glow for dot */
- --pr-notify-bg-light: rgb(from var(--ctp-latte-base) r g b / 0.85);
- --pr-notify-text-light: var(--ctp-latte-text);
- --pr-notify-border-light: rgb(from var(--ctp-latte-surface2) r g b / 0.25);
- --pr-notify-dot-color-light: var(--ctp-latte-green); /* Renamed from --ctp-latte-green for clarity */
- --pr-notify-dot-glow-light: rgb(from var(--ctp-latte-green) r g b / 0.35); /* Glow for dot */
- --pr-shadow-dark:
- 0 1px 2px rgba(0, 0, 0, 0.1),
- 0 6px 12px rgba(0, 0, 0, 0.2);
- --pr-shadow-light:
- 0 1px 2px rgba(90, 90, 90, 0.06),
- 0 6px 12px rgba(90, 90, 90, 0.12);
- }
- @keyframes pr-breathing-animation {
- 0%, 100% {
- transform: scale(0.85);
- opacity: 0.7;
- }
- 50% {
- transform: scale(1);
- opacity: 1;
- }
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} {
- position: fixed;
- bottom: 20px;
- left: 50%;
- z-index: 2147483646;
- display: flex;
- align-items: center;
- padding: 10px 16px;
- border: 1px solid var(--pr-notify-border-dark);
- border-radius: 20px;
- background-color: var(--pr-notify-bg-dark);
- color: var(--pr-notify-text-dark);
- box-shadow: var(--pr-shadow-dark);
- box-sizing: border-box;
- opacity: 0;
- font-family: ${Config.SCRIPT_SETTINGS.UI_FONT_STACK};
- text-align: left;
- backdrop-filter: blur(16px) saturate(180%);
- -webkit-backdrop-filter: blur(16px) saturate(180%);
- transform: translate(-50%, calc(100% + 40px));
- transition: transform ${animationDuration}ms ${easeOutQuint},
- opacity ${animationDuration * 0.8}ms ${easeOutQuint};
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION}.${
- Config.CSS_CLASSES.MODE_NOTIFICATION_VISIBLE
- } {
- transform: translate(-50%, 0);
- opacity: 1;
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} .${
- Config.CSS_CLASSES.BREATHING_DOT
- } {
- width: 8px;
- height: 8px;
- margin-right: 10px;
- border-radius: 50%;
- background-color: var(--pr-notify-dot-color-dark);
- box-shadow: 0 0 8px 3px var(--pr-notify-dot-glow-dark); /* Added glow */
- flex-shrink: 0;
- animation: pr-breathing-animation 2000ms ease-in-out infinite;
- /* No transition needed here as dot color doesn't change based on state for PR */
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} .${
- Config.CSS_CLASSES.MODE_NOTIFICATION_MESSAGE
- } {
- color: var(--pr-notify-text-dark);
- font-size: 13px;
- font-weight: 500;
- line-height: 1.2;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- @media (prefers-color-scheme: light) {
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} {
- border: 1px solid var(--pr-notify-border-light);
- background-color: var(--pr-notify-bg-light);
- color: var(--pr-notify-text-light);
- box-shadow: var(--pr-shadow-light);
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} .${
- Config.CSS_CLASSES.BREATHING_DOT
- } {
- background-color: var(--pr-notify-dot-color-light);
- box-shadow: 0 0 8px 3px var(--pr-notify-dot-glow-light); /* Added glow for light mode */
- }
- #${Config.ELEMENT_IDS.MODE_NOTIFICATION} .${
- Config.CSS_CLASSES.MODE_NOTIFICATION_MESSAGE
- } {
- color: var(--pr-notify-text-light);
- }
- }
- `;
- try {
- GM_addStyle(baseCSS);
- } catch (e) {}
- },
- displayModeNotification(messageKey) {
- if (this.notificationTimer) clearTimeout(this.notificationTimer);
- if (this.notificationRemovalTimer)
- clearTimeout(this.notificationRemovalTimer);
- this.notificationTimer = null;
- this.notificationRemovalTimer = null;
- const message = State.getLocalizedString(messageKey) || messageKey;
- const renderNotification = () => {
- let notificationElement = document.getElementById(
- Config.ELEMENT_IDS.MODE_NOTIFICATION
- );
- if (!notificationElement && document.body) {
- notificationElement = document.createElement("div");
- notificationElement.id = Config.ELEMENT_IDS.MODE_NOTIFICATION;
- notificationElement.innerHTML = `
- <div class="${Config.CSS_CLASSES.BREATHING_DOT}"></div>
- <div class="${Config.CSS_CLASSES.MODE_NOTIFICATION_MESSAGE}"></div>
- `.trim();
- document.body.appendChild(notificationElement);
- } else if (!notificationElement) {
- return;
- }
- const messageElement = notificationElement.querySelector(
- `.${Config.CSS_CLASSES.MODE_NOTIFICATION_MESSAGE}`
- );
- if (messageElement) messageElement.textContent = message;
- // PR script's dot color does not change based on a disabled class,
- // so no need to add/remove a .disabled class here for the dot.
- // The glow is always based on the primary dot color (green).
- notificationElement.classList.remove(
- Config.CSS_CLASSES.MODE_NOTIFICATION_VISIBLE
- );
- void notificationElement.offsetWidth;
- requestAnimationFrame(() => {
- const currentElement = document.getElementById(
- Config.ELEMENT_IDS.MODE_NOTIFICATION
- );
- if (currentElement) {
- currentElement.classList.add(
- Config.CSS_CLASSES.MODE_NOTIFICATION_VISIBLE
- );
- }
- });
- this.notificationTimer = setTimeout(() => {
- const currentElement = document.getElementById(
- Config.ELEMENT_IDS.MODE_NOTIFICATION
- );
- if (currentElement) {
- currentElement.classList.remove(
- Config.CSS_CLASSES.MODE_NOTIFICATION_VISIBLE
- );
- this.notificationRemovalTimer = setTimeout(() => {
- document
- .getElementById(Config.ELEMENT_IDS.MODE_NOTIFICATION)
- ?.remove();
- this.notificationTimer = null;
- this.notificationRemovalTimer = null;
- }, Config.SCRIPT_SETTINGS.ANIMATION_DURATION_MS);
- } else {
- this.notificationTimer = null;
- this.notificationRemovalTimer = null;
- }
- }, Config.SCRIPT_SETTINGS.NOTIFICATION_VISIBILITY_DURATION_MS);
- };
- renderNotification();
- },
- updateUserScriptMenuCommands() {
- this.registeredMenuCommandIds.forEach((id) => {
- try {
- GM_unregisterMenuCommand(id);
- } catch (e) {}
- });
- this.registeredMenuCommandIds = [];
- Config.VALID_MODES.forEach((mode) => {
- const menuKey = Config.MODE_TO_MENU_TEXT_KEY_MAP[mode];
- const baseText = State.getLocalizedString(menuKey);
- const commandText =
- baseText + (mode === State.currentMode ? " ✅" : "");
- try {
- const commandId = GM_registerMenuCommand(commandText, () =>
- ScriptManager.setModeAndUpdate(mode)
- );
- this.registeredMenuCommandIds.push(commandId);
- } catch (e) {}
- });
- },
- };
- const InputManager = {
- processPasswordInput(input, mode) {
- if (
- !(input instanceof HTMLInputElement) ||
- input.type === "hidden" ||
- input.getAttribute(Config.ATTRIBUTES.PROCESSED) === mode
- ) {
- return;
- }
- if (mode === Config.MODES.ALWAYS_SHOW) {
- input.type = "text";
- } else {
- if (input.type !== "password") {
- input.type = "password";
- }
- }
- input.setAttribute(Config.ATTRIBUTES.PROCESSED, mode);
- },
- findAndProcessNewInputs(rootNode, mode) {
- if (!rootNode || typeof rootNode.querySelectorAll !== "function") return;
- try {
- const query = `input[type="password"]:not([${Config.ATTRIBUTES.PROCESSED}="${mode}"]), input[${Config.ATTRIBUTES.PROCESSED}]:not([${Config.ATTRIBUTES.PROCESSED}="${mode}"])`;
- rootNode.querySelectorAll(query).forEach((input) => {
- this.processPasswordInput(input, mode);
- });
- const elementsToCheckForShadow =
- rootNode === document ||
- rootNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
- ? rootNode.querySelectorAll("*")
- : [rootNode];
- elementsToCheckForShadow.forEach((el) => {
- if (
- el.shadowRoot &&
- typeof el.shadowRoot.querySelectorAll === "function"
- ) {
- this.findAndProcessNewInputs(el.shadowRoot, mode);
- }
- });
- } catch (e) {}
- },
- applyCurrentModeToAllInputs() {
- try {
- this.findAndProcessNewInputs(document, State.currentMode);
- document.querySelectorAll("*").forEach((el) => {
- if (el.shadowRoot) {
- this.findAndProcessNewInputs(el.shadowRoot, State.currentMode);
- }
- });
- } catch (e) {}
- },
- };
- const EventManager = {
- domMutationObserver: null,
- handleShowPasswordOnHover(event) {
- const input = event.target;
- if (
- State.currentMode === Config.MODES.HOVER &&
- input instanceof HTMLInputElement &&
- input.matches(
- `input[type="password"][${Config.ATTRIBUTES.PROCESSED}="${Config.MODES.HOVER}"]`
- )
- ) {
- input.type = "text";
- }
- },
- handleHidePasswordOnLeave(event) {
- const input = event.target;
- if (
- State.currentMode === Config.MODES.HOVER &&
- input instanceof HTMLInputElement &&
- input.matches(
- `input[type="text"][${Config.ATTRIBUTES.PROCESSED}="${Config.MODES.HOVER}"]`
- )
- ) {
- input.type = "password";
- }
- },
- handleTogglePasswordOnDoubleClick(event) {
- const input = event.target;
- if (
- State.currentMode === Config.MODES.DBLCLICK &&
- input instanceof HTMLInputElement &&
- input.matches(
- `input[${Config.ATTRIBUTES.PROCESSED}="${Config.MODES.DBLCLICK}"]`
- )
- ) {
- input.type = input.type === "password" ? "text" : "password";
- }
- },
- handleFocusIn(event) {
- const input = event.target;
- if (
- State.currentMode === Config.MODES.FOCUS &&
- input instanceof HTMLInputElement &&
- input.matches(
- `input[type="password"][${Config.ATTRIBUTES.PROCESSED}="${Config.MODES.FOCUS}"]`
- )
- ) {
- input.type = "text";
- }
- },
- handleFocusOut(event) {
- const input = event.target;
- if (
- State.currentMode === Config.MODES.FOCUS &&
- input instanceof HTMLInputElement &&
- input.matches(
- `input[type="text"][${Config.ATTRIBUTES.PROCESSED}="${Config.MODES.FOCUS}"]`
- )
- ) {
- input.type = "password";
- }
- },
- handleKeyboardShortcut(event) {
- if (
- (event.ctrlKey || event.metaKey) &&
- event.altKey &&
- !event.shiftKey &&
- event.code === "KeyP"
- ) {
- event.preventDefault();
- event.stopPropagation();
- const currentIndex = Config.VALID_MODES.indexOf(State.currentMode);
- const nextIndex = (currentIndex + 1) % Config.VALID_MODES.length;
- const nextMode = Config.VALID_MODES[nextIndex];
- ScriptManager.setModeAndUpdate(nextMode);
- }
- },
- handleDOMMutation(mutationsList) {
- for (const mutation of mutationsList) {
- if (mutation.type === "childList") {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeType !== Node.ELEMENT_NODE) return;
- try {
- InputManager.findAndProcessNewInputs(node, State.currentMode);
- } catch (e) {}
- });
- } else if (
- mutation.type === "attributes" &&
- mutation.attributeName === "type"
- ) {
- const targetInput = mutation.target;
- if (
- targetInput.nodeType === Node.ELEMENT_NODE &&
- targetInput.matches &&
- targetInput.matches('input[type="password"]') &&
- targetInput.getAttribute(Config.ATTRIBUTES.PROCESSED) !==
- State.currentMode
- ) {
- try {
- InputManager.processPasswordInput(targetInput, State.currentMode);
- } catch (e) {}
- }
- }
- }
- },
- initializeDOMObserver() {
- if (this.domMutationObserver) return;
- const observerOptions = {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ["type"],
- };
- this.domMutationObserver = new MutationObserver(
- this.handleDOMMutation.bind(this)
- );
- if (document.body) {
- try {
- this.domMutationObserver.observe(document.body, observerOptions);
- } catch (error) {
- this.domMutationObserver = null;
- }
- } else {
- document.addEventListener(
- "DOMContentLoaded",
- () => {
- if (document.body) {
- try {
- this.domMutationObserver.observe(
- document.body,
- observerOptions
- );
- } catch (error) {
- this.domMutationObserver = null;
- }
- }
- },
- { once: true }
- );
- }
- },
- initializeGlobalEventListeners() {
- document.body.addEventListener(
- "mouseenter",
- this.handleShowPasswordOnHover.bind(this),
- true
- );
- document.body.addEventListener(
- "mouseleave",
- this.handleHidePasswordOnLeave.bind(this),
- true
- );
- document.body.addEventListener(
- "dblclick",
- this.handleTogglePasswordOnDoubleClick.bind(this)
- );
- document.addEventListener("focus", this.handleFocusIn.bind(this), true);
- document.addEventListener("blur", this.handleFocusOut.bind(this), true);
- document.addEventListener(
- "keydown",
- this.handleKeyboardShortcut.bind(this),
- true
- );
- },
- init() {
- this.initializeGlobalEventListeners();
- this.initializeDOMObserver();
- },
- };
- const ScriptManager = {
- init() {
- try {
- UserInterface.injectCoreStyles();
- State.loadAndSetInitialState();
- UserInterface.updateUserScriptMenuCommands();
- InputManager.applyCurrentModeToAllInputs();
- EventManager.init();
- } catch (error) {}
- },
- setModeAndUpdate(newMode) {
- if (State.setMode(newMode)) {
- const alertMessageKey =
- Config.MODE_TO_ALERT_MESSAGE_KEY_MAP[State.currentMode];
- UserInterface.displayModeNotification(alertMessageKey);
- InputManager.applyCurrentModeToAllInputs();
- UserInterface.updateUserScriptMenuCommands();
- }
- },
- };
- ScriptManager.init();
- })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址