pia autofill

Automatically fills and saves application data using separate Fill and Save buttons.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         pia autofill
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Automatically fills and saves application data using separate Fill and Save buttons.
// @author       Misaka_ZeroTwo
// @match        https://va.pia.jp/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

// --- CONFIGURATION ---
const STORAGE_KEY = 'piaAutofillData';

// === DEFAULT USER DATA (Used if no data in localStorage) ===
// NOTE: Use a unique variable name to avoid confusion with the loaded data
const defaultFormData = {
    // お客様情報 (Customer Info)
    cstmr_lnm: '山田',      // 姓 (Last Name/Family Name)
    cstmr_fnm: '太郎',      // 名 (First Name/Given Name)
    cstmr_lkn: 'ヤマダ',    // セイ (Last Name Katakana)
    cstmr_fkn: 'タロウ',    // メイ (First Name Katakana)

    // 性別 (Gender): '2': Female, '1': Male, '8': Others, '9': Prefer not answer
    sex_typ: '1',

    // 生年月日 (Date of Birth) - Use options from the select menus
    birth_yyyy: '1990',
    birth_mm: '05',
    birth_dd: '25',

    // 電話番号 (Phone Number)
    telno1: '090',
    telno2: '1234',
    telno3: '5678',

    // Email Address
    email: '[email protected]',

    // Address (All address fields use 'cmnt' names)
    postcode1: '221',       // 郵便番号上3桁 - cmnt01
    postcode2: '0013',      // 郵便番号下4桁 - cmnt02
    prefecture: '神奈川県',   // 都道府県 - cmnt11 (MUST MATCH AN <option> VALUE)
    city: '横浜市神奈川区',         // 市町村 - cmnt12
    district: '新子安',   // 町名 - cmnt13
    street: '4-5-6'         // 丁目・番地・号 - cmnt14
};

// =================================================================
// --- HELPER FUNCTIONS ---
// =================================================================

/**
 * Helper function to set value and trigger change events on form elements.
 */
const setInputValue = (selector, value) => {
    const element = document.querySelector(selector);
    if (element) {
        element.value = value;
        // Crucial for form validation to think a user typed the info
        ['input', 'change'].forEach(eventType => {
            const event = new Event(eventType, { bubbles: true });
            element.dispatchEvent(event);
        });
        return true;
    }
    return false;
};

/**
 * Helper function to get value from a form element.
 */
const getInputValue = (selector, isRadio = false) => {
    if (isRadio) {
        // For radio buttons, we want the value of the CHECKED one
        const checkedRadio = document.querySelector(`${selector}:checked`);
        return checkedRadio ? checkedRadio.value : '';
    }
    const element = document.querySelector(selector);
    return element ? element.value : '';
};


// =================================================================
// --- LOCALSTORAGE & DATA MANAGEMENT ---
// =================================================================

/**
 * Loads form data from localStorage, falling back to default data if empty.
 * @returns {Object} The form data.
 */
function loadFormData() {
    try {
        const storedData = localStorage.getItem(STORAGE_KEY);
        if (storedData) {
            console.log("Data loaded from localStorage.");
            return JSON.parse(storedData);
        }
    } catch (e) {
        console.error("Error loading from localStorage:", e);
    }
    console.log("No data found in localStorage. Using default data.");
    return defaultFormData;
}

/**
 * Saves the provided data into localStorage.
 * @param {Object} data - The data object to save.
 */
function saveFormData(data) {
    try {
        localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
        console.log("✅ Form data saved to localStorage.");
        alert("✅ Current form data saved successfully!");
    } catch (e) {
        console.error("Error saving to localStorage:", e);
        alert("🚨 Failed to save data. Please check the console.");
    }
}


// =================================================================
// --- FILL & RETRIEVE LOGIC ---
// =================================================================

/**
 * Fills the form using the provided data.
 * @param {Object} data - The data object to fill the form with.
 */
function fillForm(data) {
    console.clear();
    console.log("🚀 Starting form fill...");

    // Existing Fields (cstmr prefix)
    setInputValue('input[name="cstmr_lnm"]', data.cstmr_lnm);
    setInputValue('input[name="cstmr_fnm"]', data.cstmr_fnm);
    setInputValue('input[name="cstmr_lkn"]', data.cstmr_lkn);
    setInputValue('input[name="cstmr_fkn"]', data.cstmr_fkn);
    setInputValue('select[name="birth_yyyy"]', data.birth_yyyy);
    setInputValue('select[name="birth_mm"]', data.birth_mm);
    setInputValue('select[name="birth_dd"]', data.birth_dd);
    setInputValue('input[name="telno1"]', data.telno1);
    setInputValue('input[name="telno2"]', data.telno2);
    setInputValue('input[name="telno3"]', data.telno3);

    // Radio Button (Sex/Gender)
    const sexRadio = document.querySelector(`input[name="sex_typ"][value="${data.sex_typ}"]`);
    if (sexRadio) {
        sexRadio.checked = true;
        sexRadio.dispatchEvent(new Event('change', { bubbles: true }));
    }

    // Email Address (ml_addr and ml_addr_cnfm)
    setInputValue('input[name="ml_addr"]', data.email);
    setInputValue('input[name="ml_addr_cnfm"]', data.email); // Fills confirm email too!

    // Postcode (cmnt01 and cmnt02)
    setInputValue('input[name="cmnt01"]', data.postcode1);
    setInputValue('input[name="cmnt02"]', data.postcode2);

    // Address (cmnt11, cmnt12, cmnt13, and cmnt14)
    setInputValue('select[name="cmnt11"]', data.prefecture); // Prefecture (Select dropdown)
    setInputValue('input[name="cmnt12"]', data.city);        // City/Ward (Text input)
    setInputValue('input[name="cmnt13"]', data.district);    // District (Text input)
    setInputValue('input[name="cmnt14"]', data.street);      // Street/Apartment (Text input - cmnt14)

    console.log("✅ Autofill script completed. You can now edit and save the form data.");
}

/**
 * Retrieves the current form data from the page fields.
 * @returns {Object} The data object containing current field values.
 */
function retrieveForm() {
    return {
        cstmr_lnm: getInputValue('input[name="cstmr_lnm"]'),
        cstmr_fnm: getInputValue('input[name="cstmr_fnm"]'),
        cstmr_lkn: getInputValue('input[name="cstmr_lkn"]'),
        cstmr_fkn: getInputValue('input[name="cstmr_fkn"]'),
        sex_typ: getInputValue('input[name="sex_typ"]', true), // isRadio = true
        birth_yyyy: getInputValue('select[name="birth_yyyy"]'),
        birth_mm: getInputValue('select[name="birth_mm"]'),
        birth_dd: getInputValue('select[name="birth_dd"]'),
        telno1: getInputValue('input[name="telno1"]'),
        telno2: getInputValue('input[name="telno2"]'),
        telno3: getInputValue('input[name="telno3"]'),
        email: getInputValue('input[name="ml_addr"]'), // Using the main email field
        postcode1: getInputValue('input[name="cmnt01"]'),
        postcode2: getInputValue('input[name="cmnt02"]'),
        prefecture: getInputValue('select[name="cmnt11"]'),
        city: getInputValue('input[name="cmnt12"]'),
        district: getInputValue('input[name="cmnt13"]'),
        street: getInputValue('input[name="cmnt14"]'),
    };
}


// =================================================================
// --- BUTTON LOGIC AND INITIALIZATION ---
// =================================================================

const buttonContainer = document.createElement('div');
buttonContainer.style.cssText = `
    position: fixed;
    top: 10px;
    right: 10px;
    z-index: 9999;
    display: flex; /* Use flexbox to align buttons */
    gap: 10px;    /* Space between buttons */
`;

const baseButtonStyle = `
    padding: 10px 15px;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
    font-weight: bold;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
`;

// 1. Create the FILL button
const fillButton = document.createElement('button');
fillButton.id = 'autofill-script-fill-button';
fillButton.textContent = '🚀 Autofill Form';
fillButton.style.cssText = baseButtonStyle + `background-color: #007bff;`; // Blue

fillButton.addEventListener('click', () => {
    // 1. Load data from storage (or default)
    const data = loadFormData();

    // 2. Fill the form
    fillForm(data);

    // 3. Show the save button
    saveButton.style.display = 'block';
});

// 2. Create the SAVE button
const saveButton = document.createElement('button');
saveButton.id = 'autofill-script-save-button';
saveButton.textContent = '💾 Save Edits';
saveButton.style.cssText = baseButtonStyle + `background-color: #28a745;`; // Green

saveButton.addEventListener('click', () => {
    // 1. Retrieve current data from form fields
    const currentData = retrieveForm();

    // 2. Save the retrieved data to storage
    saveFormData(currentData);
});

// 3. Initial state: Hide the save button
saveButton.style.display = 'none';

// 4. Add buttons to the container
buttonContainer.appendChild(fillButton);
buttonContainer.appendChild(saveButton);

// 5. Add the container to the page body
document.body.appendChild(buttonContainer);

console.log('Autofill and Save buttons added. Click "🚀 Autofill Form" first. The "💾 Save Edits" button will appear after filling.');