记录账号和密码

记录网站密码信息并自动填充

目前為 2024-08-07 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         记录账号和密码
// @version      0.5.1
// @description  记录网站密码信息并自动填充
// @author       niweizhuan
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_addStyle
// @grant        unsafeWindow
// @license      MIT
// @namespace https://bbs.tampermonkey.net.cn/
// ==/UserScript==

(function() {
    'use strict';

    // 是否自动填充密码
    var autoFillEnabled = true;
    // 当前显示的页面索引
    var currentPageIndex = 0;
    // 显示区域的 DOM 元素
    var displayAreaDiv;
    // 当前网站域名
    var currentDomain = getCurrentDomain();

    // 获取当前网站的域名
    function getCurrentDomain() {
        return window.location.hostname;
    }

    var prevPageButton;
    var nextPageButton;

    // 获取存储的数据
    function getStoredData(domain) {
        var data = GM_getValue(domain);
        if (!data) return { accounts: [], priority: 0 }; // 如果没有数据,返回默认值
        data = JSON.parse(data);
        // 确保优先级字段存在
        if (typeof data.priority === 'undefined') data.priority = 0;
        return data;
    }

    // 设置存储的数据
    function setStoredData(domain, data) {
        GM_setValue(domain, JSON.stringify(data)); // 将数据存储为 JSON 字符串
    }

    // 创建显示区域
    function createDisplayArea() {
        if (displayAreaDiv) {
            document.body.removeChild(displayAreaDiv); // 移除现有显示区域
        }

        // 创建新的显示区域
        displayAreaDiv = document.createElement("div");
        displayAreaDiv.setAttribute("class", "passwordDisplayArea");
        displayAreaDiv.style.display = "none"; // 初始隐藏
        displayAreaDiv.style.position = "fixed";
        displayAreaDiv.style.bottom = "70px";
        displayAreaDiv.style.right = "20px";
        displayAreaDiv.style.background = "skyblue";
        displayAreaDiv.style.padding = "5px";
        displayAreaDiv.style.border = "1px solid #ccc";
        displayAreaDiv.style.zIndex = "2147483647"; // 确保显示在最上层
        displayAreaDiv.style.maxWidth = "250px";
        displayAreaDiv.style.fontSize = "14px";

        var topButtons = document.createElement("div");
        topButtons.style.display = "flex";
        topButtons.style.justifyContent = "space-between";
        topButtons.style.marginBottom = "5px";

        // 添加关闭按钮
        topButtons.appendChild(createButton("关闭", function() {
            displayAreaDiv.style.display = "none"; // 隐藏显示区域
        }));

        // 添加编辑按钮
        topButtons.appendChild(createButton("编辑", function() {
            displayAreaDiv.style.display = "none"; // 隐藏显示区域
            var storedData = getStoredData(currentDomain);
            var accountInfo = storedData.accounts[currentPageIndex];
            showEditPage(accountInfo); // 显示编辑页面
        }));

        // 添加新建按钮
        topButtons.appendChild(createButton("新建", function() {
            displayAreaDiv.style.display = "none"; // 隐藏显示区域
            showNewPage(); // 显示新建页面
        }));

        displayAreaDiv.appendChild(topButtons);

        // 显示当前网站域名
        var domainContainer = document.createElement("div");
        domainContainer.style.display = "flex";
        domainContainer.style.alignItems = "center";
        domainContainer.appendChild(createLabel("当前网站:"));
        domainContainer.appendChild(createValue(currentDomain));
        displayAreaDiv.appendChild(domainContainer);

        // 创建账号信息容器
        var accountContainer = document.createElement("div");
        accountContainer.setAttribute("class", "accountContainer");
        displayAreaDiv.appendChild(accountContainer);

        // 创建页面控制按钮
        var pageControls = document.createElement("div");
        pageControls.style.display = "flex";
        pageControls.style.justifyContent = "center";
        pageControls.style.marginTop = "5px";

        // 上一页按钮
        prevPageButton = createButton("<", function() {
            if (currentPageIndex > 0) {
                currentPageIndex--; // 转到上一页
                updateAccountDisplay();
            }
        });
        pageControls.appendChild(prevPageButton);

        // 显示当前页数的标签
        var pageLabel = document.createElement("span");
        pageLabel.setAttribute("class", "pageLabel");
        pageLabel.style.margin = "0 10px";
        pageControls.appendChild(pageLabel);

        // 下一页按钮
        nextPageButton = createButton(">", function() {
            var storedData = getStoredData(currentDomain);
            if ((currentPageIndex + 1) < storedData.accounts.length) { // 确保不要超过帐户数量
                currentPageIndex++; // 转到下一页
                updateAccountDisplay();
            }
        });
        pageControls.appendChild(nextPageButton);

        displayAreaDiv.appendChild(pageControls); // 将页面控制按钮添加到显示区域

        document.body.appendChild(displayAreaDiv); // 将显示区域添加到页面

        updateAccountDisplay(); // 更新账号信息显示
    }

    // 创建按钮
    function createButton(text, clickHandler) {
        var button = document.createElement("button");
        button.textContent = text;
        button.style.cursor = "pointer";
        button.style.backgroundColor = "transparent";
        button.style.border = "none";
        button.style.fontSize = "inherit";
        button.style.color = "#333";
        button.style.margin = "0 5px";
        button.style.padding = "3px 5px";
        button.onclick = clickHandler; // 绑定点击事件
        button.ontouchend = clickHandler; // 兼容触摸事件
        return button;
    }

    // 创建标签
    function createLabel(text) {
        var label = document.createElement("p");
        label.textContent = text;
        label.style.margin = "0"; // 无外边距
        return label;
    }

    // 创建值显示
    function createValue(text) {
        var value = document.createElement("p");
        value.textContent = text;
        value.style.margin = "0 5px"; // 设置左右间距
        return value;
    }

    // 创建没有信息的文本
    function createNoInfoText(text) {
        var noInfoText = document.createElement("p");
        noInfoText.textContent = text;
        noInfoText.style.margin = "0"; // 无外边距
        return noInfoText;
    }

    // 创建复制按钮
    function createCopyButton(text, copyText) {
        var button = document.createElement("button");
        button.textContent = text;
        button.style.cursor = "pointer";
        button.style.backgroundColor = "transparent";
        button.style.border = "none";
        button.style.fontSize = "inherit";
        button.style.color = "#333";
        button.style.marginLeft = "5px"; // 左侧间距
        button.style.padding = "3px 5px";
        button.onclick = function() {
            copyTextToClipboard(copyText, button); // 点击时复制文本
        };
        button.ontouchend = button.onclick; // 兼容触摸事件
        return button;
    }

    // 复制文本到剪贴板
    function copyTextToClipboard(text, button) {
        navigator.clipboard.writeText(text).then(function() {
            var originalText = button.textContent;
            button.textContent = "已复制"; // 显示已复制状态
            setTimeout(function() {
                button.textContent = originalText; // 恢复按钮文本
            }, 2000);
        }).catch(function(err) {
            console.error('复制失败:', err); // 复制失败时输出错误
        });
    }

    // 填充编辑页面字段
    function populateEditFieldsWithCurrentAccount() {
        var storedData = getStoredData(currentDomain);
        var currentAccount = storedData.accounts[currentPageIndex];

        var usernameField = document.getElementById("editUsername");
        var passwordField = document.getElementById("editPassword");

        usernameField.value = currentAccount.username || ""; // 填充用户名
        passwordField.value = currentAccount.password || ""; // 填充密码
    }

    // 更新账号显示
    function updateAccountDisplay() {
        var storedData = getStoredData(currentDomain);
        var accountContainer = displayAreaDiv.querySelector(".accountContainer");
        accountContainer.innerHTML = ""; // 清空当前显示内容

        if (storedData.accounts.length > 0) {
            var accountInfo = storedData.accounts[currentPageIndex];
            var accountRow = document.createElement("div");
            accountRow.style.display = "flex";
            accountRow.style.justifyContent = "space-between";

            accountRow.appendChild(createLabel("账号:")); // 账号标签
            accountRow.appendChild(createCopyButton("复制", accountInfo.username || "[无账号信息]")); // 复制按钮
            accountContainer.appendChild(accountRow);
            accountContainer.appendChild(createValue(accountInfo.username || "[无账号信息]")); // 显示账号

            var passwordRow = document.createElement("div");
            passwordRow.style.display = "flex";
            passwordRow.style.justifyContent = "space-between";
            passwordRow.appendChild(createLabel("密码:")); // 密码标签
            passwordRow.appendChild(createCopyButton("复制", accountInfo.password)); // 复制按钮
            accountContainer.appendChild(passwordRow);
            accountContainer.appendChild(createValue(accountInfo.password)); // 显示密码

            // 新增:优先级复选框
            var priorityRow = document.createElement("div");
            priorityRow.style.display = "flex"; // 确保子元素按行排列
            priorityRow.style.alignItems = "center"; // 垂直居中对齐

            var priorityCheckbox = document.createElement("input");
            priorityCheckbox.type = "checkbox";
            // 设置复选框的初始状态
            priorityCheckbox.checked = storedData.priority === currentPageIndex + 1;
            priorityCheckbox.onchange = function() {
                // 修改优先级
                if (priorityCheckbox.checked) {
                    storedData.priority = currentPageIndex + 1;
                } else {
                    storedData.priority = 0; // 取消勾选时,设置优先级为0
                }
                setStoredData(currentDomain, storedData); // 保存修改后的数据
                updateAccountDisplay(); // 更新显示
            };
            priorityRow.appendChild(priorityCheckbox);
            priorityRow.appendChild(createLabel("自动填入此页面")); // 优先级标签
            accountContainer.appendChild(priorityRow);

            fillCredentials(accountInfo.username, accountInfo.password); // 填充账号和密码
        } else {
            // 无账户信息情况
            accountContainer.appendChild(createLabel("账号:"));
            accountContainer.appendChild(createNoInfoText("[无账号信息]")); // 显示无账号信息
            accountContainer.appendChild(createLabel("密码:"));
            accountContainer.appendChild(createNoInfoText("[无密码信息]")); // 显示无密码信息
        }

        // 更新页码显示
        displayAreaDiv.querySelector(".pageLabel").textContent = (currentPageIndex + 1) + "/" + Math.ceil(storedData.accounts.length);
        prevPageButton.style.display = currentPageIndex > 0 ? "inline" : "none"; // 显示或隐藏上一页按钮
        nextPageButton.style.display = (currentPageIndex + 1) < storedData.accounts.length ? "inline" : "none"; // 显示或隐藏下一页按钮
    }

    // 显示新建页面
    function showNewPage() {
        var newDiv = document.createElement("div");
        newDiv.setAttribute("class", "passwordEditArea");
        newDiv.style.position = "fixed";
        newDiv.style.bottom = "70px";
        newDiv.style.right = "20px";
        newDiv.style.background = "white";
        newDiv.style.padding = "10px";
        newDiv.style.border = "1px solid #ccc";
        newDiv.style.zIndex = "2147483647"; // 确保显示在最上层
        newDiv.style.maxWidth = "250px";
        newDiv.style.fontSize = "14px";
        newDiv.innerHTML = `
            <p><label>账号:<input type="text" id="newUsername" style="width: 100%;"></label></p>
            <p><label>密码:<input type="password" id="newPassword" style="width: 100%;"></label></p>
            <div style="display: flex; justify-content: space-between; margin-top: 10px;">
                <button id="cancelNew">取消</button>
                <button id="saveNew">创建</button>
            </div>
        `;

        document.body.appendChild(newDiv);

        // 取消按钮事件处理程序
        document.getElementById("cancelNew").onclick = function() {
            document.body.removeChild(newDiv); // 关闭新建页面
        };

        // 保存按钮事件处理程序
        document.getElementById("saveNew").onclick = function() {
            var username = document.getElementById("newUsername").value.trim(); // 获取用户名
            var password = document.getElementById("newPassword").value; // 获取密码

            if (!validateInput(username, password)) { // 验证输入
                return;
            }

            var storedData = getStoredData(currentDomain); // 获取存储数据
            storedData.accounts.push({ username, password }); // 添加新账号信息
            setStoredData(currentDomain, storedData); // 保存数据

            document.body.removeChild(newDiv); // 关闭新建页面
            currentPageIndex = 0; // 重置页面索引
            updateAccountDisplay(); // 更新显示
        };
    }

    // 显示编辑页面
    function showEditPage(accountInfo) {
        var editDiv = document.createElement("div");
        editDiv.setAttribute("class", "passwordEditArea");
        editDiv.style.position = "fixed";
        editDiv.style.bottom = "70px";
        editDiv.style.right = "20px";
        editDiv.style.background = "white";
        editDiv.style.padding = "10px";
        editDiv.style.border = "1px solid #ccc";
        editDiv.style.zIndex = "2147483647"; // 确保显示在最上层
        editDiv.style.maxWidth = "250px";
        editDiv.style.fontSize = "14px";
        editDiv.innerHTML = `
            <p><label>账号:<input type="text" id="editUsername" style="width: 100%;" value="${accountInfo.username}"></label></p>
            <p><label>密码:<input type="password" id="editPassword" style="width: 100%;" value="${accountInfo.password}"></label></p>
            <div style="display: flex; justify-content: space-between; margin-top: 10px;">
                <button id="cancelEdit">取消</button>
                <button id="saveEdit">保存</button>
                <button id="deleteEntry">删除</button>
            </div>
        `;

        document.body.appendChild(editDiv); // 添加编辑页面

        // 取消按钮事件处理程序
        document.getElementById("cancelEdit").onclick = function() {
            document.body.removeChild(editDiv); // 关闭编辑页面
        };

        // 保存按钮事件处理程序
        document.getElementById("saveEdit").onclick = function() {
            var username = document.getElementById("editUsername").value.trim(); // 获取用户名
            var password = document.getElementById("editPassword").value; // 获取密码

            if (!validateInput(username, password)) { // 验证输入
                return;
            }

            var storedData = getStoredData(currentDomain); // 获取存储数据
            storedData.accounts[currentPageIndex] = { username, password }; // 更新账号信息
            setStoredData(currentDomain, storedData); // 保存数据

            document.body.removeChild(editDiv); // 关闭编辑页面
            currentPageIndex = 0; // 重置页面索引
            updateAccountDisplay(); // 更新显示
        };

        // 删除按钮事件处理程序
        document.getElementById("deleteEntry").onclick = function() {
            var storedData = getStoredData(currentDomain); // 获取存储数据
            // 检查当前条目是否为优先级条目
            if (storedData.priority === currentPageIndex + 1) {
                if (storedData.accounts.length > 1) {
                    storedData.priority = Math.max(1, currentPageIndex); // 设置优先级为当前条目的索引
                } else {
                    storedData.priority = 0; // 删除唯一条目时,优先级重置为0
                }
            }
            storedData.accounts.splice(currentPageIndex, 1); // 删除当前条目
            setStoredData(currentDomain, storedData); // 保存修改后的数据

            document.body.removeChild(editDiv); // 关闭编辑页面
            currentPageIndex = 0; // 重置页面索引
            updateAccountDisplay(); // 更新显示
        };
    }

    // 自动填充账号和密码
    function fillCredentials(username, password) {
        if (autoFillEnabled) { // 检查是否启用自动填充
            var editAreaExists = document.querySelector(".passwordEditArea");
            if (editAreaExists) {
                return; // 如果编辑区域已存在,则不执行填充
            }

            var storedData = getStoredData(currentDomain); // 获取存储数据
            if (storedData.priority > 0) { // 如果优先级大于0,则填充优先级账号
                var priorityAccount = storedData.accounts[storedData.priority - 1];
                username = priorityAccount.username;
                password = priorityAccount.password;
            }

            // 填充输入框
            var usernameField = document.querySelector("input[type='text'], input[type='email']");
            var passwordField = document.querySelector("input[type='password']");
            if (usernameField && passwordField) {
                usernameField.value = username;
                passwordField.value = password;
            }
        }
    }

    // 验证输入
    function validateInput(username, password) {
        return true; // 暂时不使用详细的验证逻辑
    }

    // 创建控制按钮
    function createControlButton() {
        var controlButton = document.createElement("button");
        controlButton.textContent = "显示账号和密码";
        controlButton.style.position = "fixed";
        controlButton.style.bottom = "10px";
        controlButton.style.right = "10px";
        controlButton.style.fontSize = "10px"; // 设置字体大小
        controlButton.style.cursor = "pointer"; // 设置鼠标指针为手形
        controlButton.style.zIndex = "2147483647"; // 确保显示在最上层
        controlButton.onclick = function() {
            if (!displayAreaDiv) {
                createDisplayArea(); // 仅在首次点击时创建显示区域
            }
            displayAreaDiv.style.display = displayAreaDiv.style.display === "none" ? "block" : "none"; // 切换显示状态
            if (displayAreaDiv.style.display === "block") {
                updateAccountDisplay(); // 更新显示
            }
        };

        document.body.appendChild(controlButton); // 添加控制按钮
    }

    // 自动填充加载时
    function autoFillOnLoad() {
        var storedData = getStoredData(currentDomain); // 获取存储数据
        if (storedData.priority > 0) { // 如果优先级大于0,则填充优先级账号
            var priorityAccount = storedData.accounts[storedData.priority - 1];
            fillCredentials(priorityAccount.username, priorityAccount.password); // 自动填充账号和密码
        }
    }

    createControlButton(); // 创建控制按钮
    //createDisplayArea();
    autoFillOnLoad(); // 页面加载时自动填充

})();