AutoFill

自动填写表单数据的Tampermonkey脚本

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         AutoFill
// @name:zh      自动填表
// @name:en      AutoFill
// @namespace    https://github.com/mixterjim
// @version      1.2
// @author       MixterJim
// @description  自动填写表单数据的Tampermonkey脚本
// @description:en Tampermonkey Script for Autofilling Form Data
// @homepage     https://greasyfork.org/scripts/472933-autofill
// @supportURL   https://gist.github.com/mixterjim/894de1234bce1b3a2eb6a60b9ddd23a5
// @match        */*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GPL-3.0
// @history      1.2 新增自动填充开关、仅自动填充用户修改的数据
// ==/UserScript==

(function() {
    // 引入按钮组件样式
    const modalStyle = `
        /* 设置界面容器 */
        .settings-modal {
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
          z-index: 9999;
          width: 400px;
          padding: 20px;
          background-color: #fff;
          box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
          border-radius: 4px;
          display: flex;
          flex-direction: column;
          position: fixed;
          opacity: 0.8;
          transition: opacity 0.3s ease;
        }

        .settings-modal:hover {
          /* 鼠标悬停时的样式 */
          opacity: 1;
        }

        /* 标签样式 */
        .settings-label {
          font-weight: bold;
          margin-bottom: 10px;
          display: block;
        }

        /* 输入框样式 */
        .settings-input {
          width: 100%;
          padding: 8px;
          border: 1px solid #ccc;
          border-radius: 4px;
          background-color: #f8f8f8;
          color: #333;
          box-sizing: border-box;
          transition: border-color 0.3s ease;
        }

        .settings-input:focus {
          outline: none;
          border-color: #007bff;
          box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.1);
        }

        /* 按钮Div */
        .settings-buttons {
          display: flex;
        }

        /* 按钮样式 */
        .settings-button {
          flex: 1;
          padding: 8px 16px; /* 调整按钮的内边距 */
          margin-top: 10px;
          border: none;
          border-radius: 4px;
          color: #fff;
          background-color: #007bff;
          cursor: pointer;
          transition: background-color 0.3s ease;
          font-size: 14px;  /* 调整按钮的字体大小 */
        }

        .settings-button:not(:last-child) {
          margin-right: 20px;
        }

        .settings-button:hover {
          background-color: #0056b3;
        }

        .settings-button:active {
          background-color: #004f9d;
        }

        /* 关闭按钮样式 */
        .close-button {
          position: absolute;
          top: 10px;
          right: 10px;
          padding: 6px;
          border: none;
          background-color: transparent;
          color: #333;
          font-size: 18px;
          cursor: pointer;
        }

        .close-button:hover {
          color: #007bff;
        }
    `;

    // 统一字段选择器
    const FORM_SELECTOR = 'input, textarea, select';

    // 创建 Shadow DOM 容器
    const container = document.createElement('div');
    container.id = 'autofill-container';
    document.documentElement.appendChild(container);
    const shadow = container.attachShadow({mode: 'open'});

    // 创建设置按钮
    function createSettingsButton() {
        const button = document.createElement('button');
        button.innerText = 'AutoFill';
        button.style.cssText = `
            position: fixed;
            top: 10px;
            right: 10px;
            z-index: 9999;
            opacity: 0.8;
            color: gray;
            text-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
            cursor: pointer;
        `.replace(/\n\s*/g, ' ').trim();
        button.addEventListener('click', createSettingsModal);
        shadow.appendChild(button);
    }

    // 创建设置模态框
    function createSettingsModal() {
        if (shadow.querySelector('.settings-modal')) return;

        const modal = document.createElement('div');
        modal.className = 'settings-modal';
        modal.style.zIndex = '9999'; // 解决部分网站会遮挡的问题
        
        // 默认启用自动填充
        const isAuto = localStorage.getItem('autoFillEnabled') !== 'false';
        const currentDiff = getDiffData();

        modal.innerHTML = `
            <style>${modalStyle}</style> 
            <button class="close-button">×</button>
            <div class="settings-label">
                <span>表单数据:</span>
                <label class="switch-container">
                    <input type="checkbox" id="autoFillSwitch" ${isAuto ? 'checked' : ''}> 自动填充
                </label>
            </div>
            <input class="settings-input" type="text" value='${currentDiff}'>
            <div class="settings-buttons">
                <button class="settings-button btn-save">保存</button>
                <button class="settings-button btn-fill">恢复</button>
                <button class="settings-button btn-clear">清空</button>
                <button class="settings-button btn-init">初始化</button>
            </div>
        `;

        // 绑定事件
        modal.querySelector('.close-button').addEventListener('click', closeSettingsModal);
        modal.querySelector('.btn-save').addEventListener('click', saveFormData);
        modal.querySelector('.btn-fill').addEventListener('click', fillForm);
        modal.querySelector('.btn-clear').addEventListener('click', clearFormData);
        modal.querySelector('.btn-init').addEventListener('click', () => {
            captureInitialState(); 
            const inputField = modal.querySelector('.settings-input');
            if (inputField) {
                // 此处应该显示是{}
                inputField.value = getDiffData();
            }
        });
        modal.querySelector('#autoFillSwitch').addEventListener('change', (e) => {
            localStorage.setItem('autoFillEnabled', e.target.checked);
        });


        shadow.appendChild(modal);
    }

    // 关闭设置模态框
    function closeSettingsModal() {
        const modal = shadow.querySelector('.settings-modal');
        if (modal) modal.remove();
    }

    // 保存初始表单状态
    let initialFormState = {};

    // 捕获初始状态
    function captureInitialState() {
        initialFormState = {};
        const formFields = document.querySelectorAll(FORM_SELECTOR);
        formFields.forEach(field => {
            if (field.name) {
                initialFormState[field.name] = field.value;
            }
        });
        // console.log('AutoFill: 基准状态已更新', initialFormState);
    }

    // 获取表单差异数据
    function getDiffData() {
        const formFields = document.querySelectorAll(FORM_SELECTOR);
        const diffData = {};
        formFields.forEach(field => {
            if (field.name) {
                const initialVal = initialFormState[field.name];
                if (field.value !== initialVal) {
                    diffData[field.name] = field.value;
                }
            }
        });
        return JSON.stringify(diffData);
    }

    // 保存表单
    function saveFormData() {
        const inputField = shadow.querySelector('.settings-input').value.trim();
        try {
            JSON.parse(inputField);
            localStorage.setItem('formData', inputField);
        } catch (e) {
            alert('保存失败:JSON 格式不正确。');
            return;
        }
        closeSettingsModal();
    }

    // 清空表单
    function clearFormData() {
        localStorage.removeItem('formData');
        document.querySelectorAll(FORM_SELECTOR).forEach(field => {
            if(field.name && field.name in initialFormState) {
                // TODO:恢复到初始状态,而不是清空
                field.value = initialFormState[field.name];
            }
        });
        closeSettingsModal();
    }


    // 自动填充
    function fillForm() {
        const savedFormData = localStorage.getItem('formData');
        if (savedFormData) {
            try {
                const parsedData = JSON.parse(savedFormData);
                const formFields = document.querySelectorAll(FORM_SELECTOR);
                formFields.forEach(function(field) {
                    if (field.name && field.name in parsedData) {
                        field.value = parsedData[field.name];
                    }
                });
            } catch (error) { console.error('AutoFill解析失败:', error); }
        }
        if (shadow.querySelector('.settings-modal')) closeSettingsModal();
    }

    // 在页面完全加载后执行
    window.addEventListener('load', function() {
        // 记录初始状态
        captureInitialState();
        // 添加设置按钮
        createSettingsButton();
        // 自动填充表单数据
        if (localStorage.getItem('autoFillEnabled') === 'true') {
            setTimeout(fillForm, 1000);
        }
    });
})();