// ==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();
}
})();