Answer2fill (Enhanced Windows 98 Style)

auto-filling answers with enhanced Windows 98 style interface

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

// ==UserScript==
// @name         Answer2fill (Enhanced Windows 98 Style)
// @namespace    http://tampermonkey.net/
// @version      1.2.0
// @description  auto-filling answers with enhanced Windows 98 style interface
// @match        https://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(function () {
  "use strict";

  const GLOBAL = {
    fillAnswerDelay: 300,
  };

  const DEFAULT_SELECTORS = {
    "czvtc.cj-edu.com": {
      subjectContainer: ".el-container .all_subject>.el-row"
    },
    "learning.mhtall.com": {
      subjectContainer: "#div_item"
    },
    "168wangxiao.com": {
      subjectContainer: ".Answer-area"
    },
  };

  let questions = [];
  const SELECTORS = JSON.parse(
    GM_getValue("domainSelectors", JSON.stringify(DEFAULT_SELECTORS))
  );
  const currentDomain = window.location.hostname;

  // Enhanced Windows 98 style CSS
  GM_addStyle(`
    #auto-fill-container {
      font-family: 'MS Sans Serif', Arial, sans-serif;
      background-color: #c0c0c0;
      border: 2px outset #ffffff;
      box-shadow: 2px 2px 0 #000000;
      color: #000000;
    }
    #auto-fill-container button {
      font-family: 'MS Sans Serif', Arial, sans-serif;
      background-color: #c0c0c0;
      border: 2px outset #ffffff;
      padding: 2px 8px;
      margin: 2px;
      color: #000000;
      cursor: pointer;
    }
    #auto-fill-container button:active {
      border-style: inset;
    }
    #auto-fill-container input[type="text"], #auto-fill-container textarea {
      border: 2px inset #ffffff;
      background-color: #ffffff;
      padding: 2px;
    }
    .win98-tab {
      display: inline-block;
      padding: 3px 8px;
      background-color: #c0c0c0;
      border: 2px outset #ffffff;
      border-bottom: none;
      margin-right: 2px;
      cursor: pointer;
    }
    .win98-tab.active {
      background-color: #dfdfdf;
      border-style: inset;
      border-bottom: none;
    }
    #tab-content {
      border: 2px inset #ffffff;
      padding: 10px;
      background-color: #dfdfdf;
    }
    #title-bar {
      background: linear-gradient(to right, #000080, #1084d0);
      padding: 2px 4px;
      margin-bottom: 4px;
      color: #ffffff;
      font-weight: bold;
    }
    #close-button {
      float: right;
      background: #c0c0c0;
      border: 1px outset #ffffff;
      color: #000000;
      font-size: 9px;
      line-height: 1;
      padding: 1px 3px;
      font-weight: bold;
    }
    #status-bar {
      border-top: 2px groove #ffffff;
      padding: 2px 4px;
      font-size: 11px;
      margin-top: 4px;
    }
    .progress-bar {
      width: 100%;
      background-color: #ffffff;
      border: 1px inset #808080;
      height: 15px;
      margin-top: 5px;
    }
    .progress-bar-fill {
      width: 0%;
      height: 100%;
      background-color: #000080;
      transition: width 0.3s ease-in-out;
    }
  `);

  function getSelectorsForCurrentDomain() {
    return SELECTORS[currentDomain] || null;
  }

  function createMainInterface() {
    const container = document.createElement("div");
    container.id = "auto-fill-container";
    Object.assign(container.style, {
      position: "fixed",
      top: "10px",
      right: "10px",
      padding: "3px",
      borderRadius: "0",
      zIndex: "9999",
      display: GM_getValue("PanelVisible", true) ? "block" : "none",
      width: "300px"
    });

    container.innerHTML = `
      <div id="title-bar">
        <span>Auto-Fill Panel</span>
        <button id="close-button">X</button>
      </div>
      <p id="question-count">Detecting questions...</p>
      <div id="tab-buttons">
        <span id="fill-tab-button" class="win98-tab active">Fill Answers</span>
        <span id="config-tab-button" class="win98-tab">Configure</span>
      </div>
      <div id="tab-content">
        <div id="fill-tab">
          <textarea id="bulk-input" style="width:100%;height:100px;margin:10px 0;resize:none;" placeholder="Enter answers (e.g., A,B,C)"></textarea>
          <button id="fill-button" style="width:100%;">Fill Answers</button>
          <div class="progress-bar">
            <div class="progress-bar-fill"></div>
          </div>
        </div>
        <div id="config-tab" style="display:none;">
          <div id="selector-inputs"></div>
          <button id="save-selector" style="width:100%;margin-top:10px;">Save Configuration</button>
        </div>
      </div>
      <div id="status-bar">Ready</div>
    `;
    document.body.appendChild(container);

    // Event listeners
    container.addEventListener("click", handleContainerClick);
    container.addEventListener("mousedown", handleContainerMouseDown);
    document.getElementById("bulk-input").addEventListener("keydown", handleBulkInputKeydown);
    document.getElementById("close-button").addEventListener("click", togglePanelVisibility);
    updateConfigTab();
  }

  const handleContainerClick = (e) => {
    const target = e.target;
    if (target.id === "fill-tab-button" || target.id === "config-tab-button") {
      switchTab(target.id.replace("-tab-button", ""));
    } else if (target.id === "save-selector") {
      saveSelectors();
    } else if (target.id === "fill-button") {
      fillAnswers();
    }
  };

  const handleContainerMouseDown = (e) => {
    if (e.target.id === "title-bar") {
      let offsetX = e.clientX - e.target.getBoundingClientRect().left;
      let offsetY = e.clientY - e.target.getBoundingClientRect().top;
      
      function mouseMoveHandler(e) {
        const container = document.getElementById("auto-fill-container");
        container.style.right = "auto";
        container.style.left = `${e.clientX - offsetX}px`;
        container.style.top = `${e.clientY - offsetY}px`;
      }

      function mouseUpHandler() {
        document.removeEventListener("mousemove", mouseMoveHandler);
        document.removeEventListener("mouseup", mouseUpHandler);
      }

      document.addEventListener("mousemove", mouseMoveHandler);
      document.addEventListener("mouseup", mouseUpHandler);
    }
  };

  const handleBulkInputKeydown = (e) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      fillAnswers();
    }
  };

  function switchTab(tabName) {
    document.getElementById("fill-tab").style.display = tabName === "fill" ? "block" : "none";
    document.getElementById("config-tab").style.display = tabName === "config" ? "block" : "none";
    document.getElementById("fill-tab-button").classList.toggle("active", tabName === "fill");
    document.getElementById("config-tab-button").classList.toggle("active", tabName === "config");
  }

  function togglePanelVisibility() {
    const container = document.getElementById("auto-fill-container");
    const newVisibility = container.style.display === "none";
    container.style.display = newVisibility ? "block" : "none";
    GM_setValue("PanelVisible", newVisibility);
  }

  function updateConfigTab() {
    const currentSelectors = SELECTORS[currentDomain] || DEFAULT_SELECTORS[currentDomain] || {};
    document.getElementById("selector-inputs").innerHTML = `<input id="subjectContainer" type="text" style="width:100%;" value="${currentSelectors.subjectContainer || ""}" placeholder="subjectContainer">`;
  }

  function saveSelectors() {
    SELECTORS[currentDomain] = {
      subjectContainer: document.getElementById("subjectContainer").value,
    };
    GM_setValue("domainSelectors", JSON.stringify(SELECTORS));
    detectQuestions();
    switchTab("fill");
    updateStatusBar("Configuration saved");
  }

  function updateQuestionCount() {
    const countElement = document.getElementById("question-count");
    if (countElement) {
      countElement.textContent = `Detected questions: ${questions.length}`;
    }
  }

  function detectQuestions() {
    const currentSelectors = getSelectorsForCurrentDomain();
    if (currentSelectors && currentSelectors.subjectContainer) {
      questions = Array.from(
        document.querySelectorAll(currentSelectors.subjectContainer)
      ).filter(
        (item) => item.querySelectorAll('input[type="radio"],input[type="checkbox"]').length > 1
      );
    }

    if (questions.length === 0) {
      const optionsGroup = new Map();
      document.querySelectorAll('input[type="radio"],input[type="checkbox"]').forEach(opt => {
        const name = opt.getAttribute("name");
        if (name) {
          if (!optionsGroup.has(name)) {
            optionsGroup.set(name, []);
          }
          optionsGroup.get(name).push(opt);
        }
      });
      questions = Array.from(optionsGroup.values());
    }
    updateQuestionCount();
    if (questions.length === 0) switchTab("config");
  }

  function parseAnswers(input) {
    return input.replace(/\s/g, "").toUpperCase().split(",");
  }

  const fillAnswers = async () => {
    const currentSelectors = getSelectorsForCurrentDomain();
    const answers = parseAnswers(document.getElementById("bulk-input").value);
    const totalQuestions = Math.min(questions.length, answers.length);
    let completedQuestions = 0;

    updateStatusBar("Filling answers...");

    for (let i = 0; i < totalQuestions; i++) {
      const subject = currentSelectors && currentSelectors.subjectContainer ?
        Array.from(document.querySelectorAll(currentSelectors.subjectContainer))
        .filter(item => item.querySelectorAll('input[type="radio"],input[type="checkbox"]').length > 0)[i] :
        null;
      const options = subject ?
        subject.querySelectorAll('input[type="radio"],input[type="checkbox"]') :
        questions[i];
      const answer = answers[i];

      await fillAnswer(options, answer);
      completedQuestions++;
      updateProgressBar(completedQuestions / totalQuestions);
    }

    updateStatusBar("Answers filled successfully");
  };

  const fillAnswer = async (options, answer) => {
    for (const char of answer) {
      const optionIndex = char.charCodeAt(0) - 65;
      if (optionIndex >= 0 && optionIndex < options.length) {
        const option = options[optionIndex];
        if (!option.checked) {
          const clickTarget = option.style.display === "none" ? option.parentElement : option;
          clickTarget.click();
          await new Promise(resolve => setTimeout(resolve, GLOBAL.fillAnswerDelay));
        }
      }
    }
  };

  function updateProgressBar(progress) {
    const progressBarFill = document.querySelector('.progress-bar-fill');
    progressBarFill.style.width = `${progress * 100}%`;
  }

  function updateStatusBar(message) {
    const statusBar = document.getElementById('status-bar');
    statusBar.textContent = message;
  }

  function init() {
    createMainInterface();
    setTimeout(detectQuestions, 2000);
    GM_registerMenuCommand("Auto-Fill Panel", () => {
      togglePanelVisibility();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址