// ==UserScript== // @name [IJWS]I just want to study-我只是想学习 // @namespace http://tampermonkey.net/ // @version release-251206.100 // @description 组卷网辅助功能,提供刷题模式来沉浸式刷题 // @author 云氢YunHydrogen // @match *://zujuan.xkw.com/* // @icon https://www.xkw.com/favicon.ico // @grant GM_addStyle // @license AGPL-3.0 // @downloadURL https://update.greasyfork.icu/scripts/557987/%5BIJWS%5DI%20just%20want%20to%20study-%E6%88%91%E5%8F%AA%E6%98%AF%E6%83%B3%E5%AD%A6%E4%B9%A0.user.js // @updateURL https://update.greasyfork.icu/scripts/557987/%5BIJWS%5DI%20just%20want%20to%20study-%E6%88%91%E5%8F%AA%E6%98%AF%E6%83%B3%E5%AD%A6%E4%B9%A0.meta.js // ==/UserScript== (function() { 'use strict'; const cleanCss = ` /* 隐藏全局干扰元素 */ body.clean-mode .header, body.clean-mode .bread-nav, body.clean-mode .footer, body.clean-mode .fiexd-nav, body.clean-mode .ai-entry, body.clean-mode .other-info, body.clean-mode .xep-root, body.clean-mode iframe, body.clean-mode .care-mode_protect-eye, body.clean-mode .free-ad, body.clean-mode .low-browser, body.clean-mode .ques-additional, body.clean-mode .exam-item__custom, body.clean-mode .exam-item__info, body.clean-mode .sec-title .btn-box, body.clean-mode .ctrl-box { display: none !important; } /* 页面布局调整 */ body.clean-mode { background-color: #ffffff !important; overflow-x: hidden; } body.clean-mode .page.exam-detail { width: 100% !important; max-width: 950px !important; margin: 0 auto !important; padding: 5px 20px !important; background: #ffffff !important; float: none !important; } body.clean-mode .exam-cnt { width: 100% !important; float: none !important; background: transparent !important; border: none !important; box-shadow: none !important; padding: 0 !important; } body.clean-mode .page.exam-detail::before, body.clean-mode .page.exam-detail::after, body.clean-mode .page.exam-detail.clearfix::before, body.clean-mode .page.exam-detail.clearfix::after { content: none !important; display: none !important; } /* 全模式题目衬底收紧 */ .tk-quest-item, .quesroot { margin: 0 !important; padding: 0 !important; } /* 统一 wrapper/quesdiv/selected-mask 上下间距 */ .wrapper, .quesdiv, .selected-mask { margin-block: 0 !important; padding-block: 0 !important; } /* 题目样式优化 */ body.clean-mode .tk-quest-item { margin-bottom: 16px !important; padding-top: 8px !important; padding-bottom: 12px !important; border-bottom: 1px dashed #ccc !important; background: #fff !important; } body.clean-mode .tk-quest-item:hover, body.clean-mode .quesroot:hover { border: none !important; border-bottom: 1px dashed #ccc !important; box-shadow: none !important; background: #fff !important; } body.clean-mode .tk-quest-item::after, body.clean-mode .tk-quest-item::before, body.clean-mode .quesroot::after, body.clean-mode .quesroot::before { content: none !important; display: none !important; } body.clean-mode .exam-item__cnt { font-size: 16px !important; line-height: 1.8 !important; margin-top: 0 !important; margin-bottom: 0 !important; color: #000 !important; background: #ffffff !important; border: 0.5px solid #e0e7f1 !important; border-radius: 8px !important; padding: 0 16px !important; box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06) !important; } body.clean-mode .exam-item__opt { background-color: #f5f7fa !important; border: 1px solid #dde3ec !important; padding: 14px !important; border-radius: 8px !important; margin-top: 12px !important; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 6px 18px rgba(56, 103, 214, 0.08) !important; } #ijws-practice-answers .exam-item__opt { background-color: #f5f7fa !important; border: 1px solid #dde3ec !important; padding: 14px !important; border-radius: 8px !important; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 6px 18px rgba(56, 103, 214, 0.08) !important; margin-top: 6px !important; } /* 去除 selected-mask 导致的模糊和遮罩 */ body.clean-mode .selected-mask { filter: none !important; -webkit-filter: none !important; opacity: 1 !important; background: none !important; transform: none !important; position: static !important; } body.clean-mode .selected-mask::before, body.clean-mode .selected-mask::after { display: none !important; content: none !important; width: 0 !important; height: 0 !important; } /* 标题样式优化 */ body.clean-mode .sec-title { margin: 0 !important; padding: 5px 0 !important; } body.clean-mode .title-txt { font-weight: bold !important; font-family: "SimHei", "黑体", "Microsoft YaHei", sans-serif !important; font-size: 22px !important; letter-spacing: 0.5px !important; display: inline-block !important; padding: 4px 12px !important; border-radius: 6px !important; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08) !important; margin: 0 !important; } body.clean-mode .sec-title span { background: #FFCC11 !important; color: #ffffff !important; font-weight: bold !important; display: inline-block !important; font-size: 11px !important; line-height: 1.2 !important; padding: 3px 3px !important; border-radius: 3px !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; } /* 题目题号样式 (黄色衬底) */ .ijws-q-tit-num { display: none; color: #ffffff; font-weight: bold; background-color: #FFCC11; padding: 3px 3px; border-radius: 4px; margin-right: 6px; font-size: 12px; vertical-align: middle; -webkit-print-color-adjust: exact; print-color-adjust: exact; } body.clean-mode .ijws-q-tit-num { display: inline-block !important; } /* 练习模式答案区 */ .ijws-practice-hidden { display: none !important; } #ijws-practice-answers { margin-top: 40px; padding: 18px; border: 1px dashed #39C5BB; border-radius: 8px; background: #fdfefe; } #ijws-practice-answers .ijws-practice-heading { font-weight: bold; margin-bottom: 16px; color: #39C5BB; font-size: 18px; } .ijws-practice-answer { margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid #eee; } .ijws-practice-title { font-weight: bold; margin-bottom: 8px; color: #333; } /* 答案模式答案区 */ #ijws-answer-only { margin-top: 32px; padding: 18px; border: 1px dashed #FFB300; border-radius: 8px; background: #fffaf3; } #ijws-answer-only .ijws-answer-heading { font-weight: bold; margin-bottom: 16px; color: #d48806; font-size: 18px; } #ijws-answer-only .ijws-answer-item { margin-bottom: 14px; padding-bottom: 12px; border-bottom: 1px solid #f0d9a4; } #ijws-answer-only .ijws-answer-title { font-weight: bold; margin-bottom: 8px; color: #b36b00; } /* 打印优化 */ @media print { #ijws-container { display: none !important; } body.clean-mode .page.exam-detail { max-width: 100% !important; padding: 0 !important; } body.clean-mode .exam-item__opt { background-color: transparent !important; border: 1px solid #eee; } body.clean-mode .tk-quest-item { page-break-inside: avoid; } } /* 提示弹窗 */ #ijws-toast { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 10px 20px; border-radius: 20px; font-size: 14px; z-index: 2147483647; display: flex; align-items: center; gap: 8px; opacity: 0; transition: opacity 0.3s; pointer-events: none; } #ijws-toast.show { opacity: 1; } #ijws-toast svg { width: 20px; height: 20px; } /* 子菜单激活状态 */ .ijws-menu-item.active { background-color: #00FFCC !important; } `; const cursorSvg = ``; const cursorDataUrl = `data:image/svg+xml;utf8,${encodeURIComponent(cursorSvg)}`; const PRACTICE_CONTAINER_ID = 'ijws-practice-answers'; const ANSWER_CONTAINER_ID = 'ijws-answer-only'; const GITHUB_URL = 'https://github.com/Yun-Hydrogen/IJustWanttoStudy'; const uiCss = ` /* 悬浮球容器 */ #ijws-container { position: fixed; bottom: 120px; right: 120px; z-index: 2147483647; width: 50px; height: 50px; user-select: none; cursor: url('${cursorDataUrl}') 6 6, auto; } /* 主按钮 */ #ijws-main-btn { width: 100%; height: 100%; background-color: #66CCFF; border-radius: 50%; box-shadow: 0 4px 12px rgba(0,0,0,0.15); cursor: url('${cursorDataUrl}') 6 6, grab; display: flex; flex-direction: column; align-items: center; justify-content: center; color: white; font-weight: bold; font-size: 12px; position: absolute; top: 0; left: 0; z-index: 10; transition: background-color 0.3s, transform 0.2s; } #ijws-main-btn:active { cursor: url('${cursorDataUrl}') 6 6, grabbing; transform: scale(0.95); } #ijws-main-btn svg { width: 20px; height: 20px; margin-top: 2px; fill: white; } /* 菜单项 */ .ijws-menu-item { width: 32px; height: 32px; background-color: #fff; border-radius: 50%; box-shadow: 0 2px 8px rgba(0,0,0,0.2); position: absolute; top: 9px; /* (50-32)/2 */ left: 9px; display: flex; align-items: center; justify-content: center; cursor: url('${cursorDataUrl}') 6 6, pointer; opacity: 0; transform: translate(0, 0) scale(0); transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); z-index: 5; pointer-events: none; } /* 菜单展开位置 */ #ijws-container.open .ijws-menu-item { pointer-events: auto; } #ijws-container.open .ijws-menu-item:nth-of-type(2) { /* 菜单1: 左侧 */ transform: translateX(-45px) scale(1); opacity: 1; } #ijws-container.open .ijws-menu-item:nth-of-type(3) { /* 菜单2: 上方 */ transform: translateY(-45px) scale(1); opacity: 1; } #ijws-container.open .ijws-menu-item:nth-of-type(4) { /* 菜单3: 右侧 */ transform: translateX(45px) scale(1); opacity: 1; } #ijws-container.open .ijws-menu-item:nth-of-type(5) { /* 菜单4: 下方 */ transform: translateY(45px) scale(1); opacity: 1; } /* 图标 */ .ijws-menu-item svg { width: 18px; height: 18px; } .ijws-menu-item svg, .ijws-menu-item svg path { fill: #000000 !important; } /* Tooltip */ .ijws-tooltip { position: absolute; background: rgba(0,0,0,0.8); color: white; padding: 4px 8px; border-radius: 4px; font-size: 12px; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.2s; visibility: hidden; } /* Tooltip 位置 */ .ijws-menu-item:nth-of-type(2) .ijws-tooltip { /* 菜单1(左) */ right: 40px; top: 50%; transform: translateY(-50%); } .ijws-menu-item:nth-of-type(3) .ijws-tooltip { /* 菜单2(上) */ bottom: 40px; left: 50%; transform: translateX(-50%); } .ijws-menu-item:nth-of-type(4) .ijws-tooltip { /* 菜单3(右) */ left: 40px; top: 50%; transform: translateY(-50%); } .ijws-menu-item:nth-of-type(5) .ijws-tooltip { /* 菜单4(EIFORS*/ top: 40px; left: 50%; transform: translateX(-50%); } .ijws-menu-item:hover .ijws-tooltip { opacity: 1; visibility: visible; } `; const MODE = Object.freeze({ NONE: 'none', EXAM: 'exam', REFERENCE: 'reference', PRACTICE: 'practice', ANSWER: 'answer' }); const MODE_TOAST = Object.freeze({ [MODE.EXAM]: { enter: '已进入试卷模式', exit: '已退出试卷模式' }, [MODE.REFERENCE]: { enter: '已进入参考模式', exit: '已退出参考模式' }, [MODE.PRACTICE]: { enter: '已进入练习模式', exit: '已退出练习模式' }, [MODE.ANSWER]: { enter: '已进入答案模式', exit: '已退出答案模式' } }); const state = { currentMode: MODE.NONE, isDragging: false, dragStart: { x: 0, y: 0 }, initialPosition: { left: 0, top: 0 }, toastTimer: null, longPressTimer: null, mutationObserver: null }; const DOM = { container: null, mainBtn: null, toast: null, menuItems: new Map() }; const ICON = Object.freeze({ exam: ` `, reference: ` `, practice: ` `, answer: ` `, extra: ` ` }); const MENU_CONFIG = [ { mode: MODE.EXAM, tooltip: '试卷模式', icon: ICON.exam }, { mode: MODE.REFERENCE, tooltip: '参考模式', icon: ICON.reference }, { mode: MODE.PRACTICE, tooltip: '练习模式', icon: ICON.practice }, { mode: MODE.ANSWER, tooltip: '答案模式', icon: ICON.answer }, { tooltip: '备用功能', icon: ICON.extra, onClick: () => showToast('备用功能开发中,敬请期待', ICON.extra, '#409EFF') } ]; init(); function init() { injectStyles(); buildFloatingUi(); attachGlobalHandlers(); observeDynamicContent(); } function injectStyles() { const styleEl = document.createElement('style'); styleEl.id = 'clean-mode-style'; styleEl.textContent = cleanCss + uiCss; document.head.appendChild(styleEl); } function buildFloatingUi() { DOM.container = document.createElement('div'); DOM.container.id = 'ijws-container'; DOM.mainBtn = createMainButton(); DOM.container.appendChild(DOM.mainBtn); MENU_CONFIG.forEach((config) => { const item = createMenuItem(config); DOM.container.appendChild(item); if (config.mode) { DOM.menuItems.set(config.mode, { element: item, icon: config.icon }); } }); document.body.appendChild(DOM.container); DOM.toast = createToast(); } function createMainButton() { const mainBtn = document.createElement('div'); mainBtn.id = 'ijws-main-btn'; mainBtn.innerHTML = ` IJWS `; mainBtn.addEventListener('mousedown', handleMainButtonMouseDown); ['mouseup', 'mouseleave'].forEach(evt => mainBtn.addEventListener(evt, clearLongPressTimer)); mainBtn.addEventListener('contextmenu', handleContextMenuOpenGithub); mainBtn.addEventListener('click', handleMainButtonClick); return mainBtn; } function createMenuItem(config) { const item = document.createElement('div'); item.className = 'ijws-menu-item'; item.innerHTML = ` ${config.icon} ${config.tooltip} `; if (config.mode) { item.addEventListener('click', () => handleModeToggle(config.mode)); } else if (typeof config.onClick === 'function') { item.addEventListener('click', () => config.onClick()); } return item; } function createToast() { const toast = document.createElement('div'); toast.id = 'ijws-toast'; document.body.appendChild(toast); return toast; } function attachGlobalHandlers() { document.addEventListener('click', questionClickBlocker, true); } function observeDynamicContent() { state.mutationObserver = new MutationObserver(() => { if (document.body.classList.contains('clean-mode')) { processQuestionTitles(); } }); state.mutationObserver.observe(document.body, { childList: true, subtree: true }); } function handleMainButtonMouseDown(event) { state.isDragging = false; state.dragStart.x = event.clientX; state.dragStart.y = event.clientY; const rect = DOM.container.getBoundingClientRect(); state.initialPosition.left = rect.left; state.initialPosition.top = rect.top; state.longPressTimer = setTimeout(() => { if (!state.isDragging) { openGithubHome(); } }, 800); const onMouseMove = (moveEvent) => { const dx = moveEvent.clientX - state.dragStart.x; const dy = moveEvent.clientY - state.dragStart.y; if (Math.abs(dx) > 3 || Math.abs(dy) > 3) { state.isDragging = true; clearTimeout(state.longPressTimer); DOM.container.style.left = `${state.initialPosition.left + dx}px`; DOM.container.style.top = `${state.initialPosition.top + dy}px`; DOM.container.style.right = 'auto'; } }; const onMouseUp = () => { clearTimeout(state.longPressTimer); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); } function clearLongPressTimer() { clearTimeout(state.longPressTimer); } function handleContextMenuOpenGithub(event) { event.preventDefault(); openGithubHome(); } function handleMainButtonClick() { if (!state.isDragging) { DOM.container.classList.toggle('open'); } } function openGithubHome() { window.open(GITHUB_URL, '_blank'); } function questionClickBlocker(event) { if (state.currentMode === MODE.NONE) return; const target = event.target.closest('.tk-quest-item, .quesroot'); if (target) { event.stopPropagation(); event.preventDefault(); } } function handleModeToggle(mode) { const menuInfo = DOM.menuItems.get(mode); if (!menuInfo) return; const isSameMode = state.currentMode === mode; if (isSameMode) { exitMode(mode); setMode(MODE.NONE); showToast(MODE_TOAST[mode].exit, menuInfo.icon, '#f56c6c'); return; } exitMode(state.currentMode); enterMode(mode); setMode(mode); showToast(MODE_TOAST[mode].enter, menuInfo.icon, '#67c23a'); DOM.container.classList.remove('open'); } function setMode(mode) { state.currentMode = mode; DOM.menuItems.forEach((info, key) => { info.element.classList.toggle('active', key === mode); }); } function enterMode(mode) { if (mode === MODE.NONE) return; toggleCleanVisuals(true); switch (mode) { case MODE.EXAM: break; case MODE.ANSWER: // 答案模式:隐藏题目,仅保留答案列表 ensureAnswersVisible(); setTimeout(() => { if (state.currentMode === MODE.ANSWER) { buildAnswerOnlyAppendix(); } }, 400); break; case MODE.REFERENCE: ensureAnswersVisible(); setTimeout(() => { if (state.currentMode === MODE.REFERENCE) { addQuestionNumbers(); } }, 1000); break; case MODE.PRACTICE: clearPracticeArtifacts(); ensureAnswersVisible(); setTimeout(() => { if (state.currentMode === MODE.PRACTICE) { addQuestionNumbers(); moveAnswersToAppendix(); } }, 800); break; default: break; } } function exitMode(mode) { switch (mode) { case MODE.EXAM: toggleCleanVisuals(false); break; case MODE.ANSWER: clearAnswerModeArtifacts(); resetReferenceArtifacts(); toggleCleanVisuals(false); break; case MODE.REFERENCE: toggleCleanVisuals(false); resetReferenceArtifacts(); break; case MODE.PRACTICE: toggleCleanVisuals(false); clearPracticeArtifacts(); resetReferenceArtifacts(); break; default: break; } } function showToast(message, iconSvg, iconColor) { if (!DOM.toast) return; const processedSvg = iconSvg .replace(/fill="[^"]*"/g, '') .replace('${message} `; DOM.toast.classList.add('show'); if (state.toastTimer) clearTimeout(state.toastTimer); state.toastTimer = setTimeout(() => { DOM.toast.classList.remove('show'); }, 3000); } function toggleCleanVisuals(enable) { document.body.classList.toggle('clean-mode', enable); if (DOM.mainBtn) { DOM.mainBtn.style.backgroundColor = enable ? '#39C5BB' : '#66CCFF'; } document.querySelectorAll('.selected-mask').forEach(el => { if (enable) { el.style.filter = 'none'; el.style.opacity = '1'; } else { el.style.filter = ''; el.style.opacity = ''; } }); if (enable) { processQuestionTitles(); } } function processQuestionTitles() { document.querySelectorAll('.ijws-q-tit-num').forEach(el => el.remove()); } function addQuestionNumbers() { document.querySelectorAll('.tk-quest-item').forEach((item, index) => { const answerBlock = item.querySelector('.exam-item__opt') || item.querySelector('.exam-item__analyze'); if (!answerBlock || answerBlock.querySelector('.ijws-q-num')) { return; } const num = document.createElement('div'); num.className = 'ijws-q-num'; num.innerHTML = `第 ${index + 1} 题`; Object.assign(num.style, { color: '#ffffff', backgroundColor: '#FF6699', display: 'inline-block', padding: '2px 6px', borderRadius: '4px', marginBottom: '3px', fontSize: '12px' }); num.style.setProperty('-webkit-print-color-adjust', 'exact'); num.style.setProperty('print-color-adjust', 'exact'); answerBlock.insertBefore(num, answerBlock.firstChild); }); } function removeQuestionNumbers() { document.querySelectorAll('.ijws-q-num').forEach(el => el.remove()); } function ensureAnswersVisible() { const showAnswerBtn = document.querySelector('.tklabel-checkbox.show-answer.checkbox-default'); if (showAnswerBtn && !showAnswerBtn.classList.contains('checked')) { showAnswerBtn.click(); } } function clearPracticeArtifacts() { document.querySelectorAll('.ijws-practice-hidden').forEach(el => el.classList.remove('ijws-practice-hidden')); const appendix = document.getElementById(PRACTICE_CONTAINER_ID); if (appendix) { appendix.remove(); } } function moveAnswersToAppendix() { const host = document.querySelector('.page.exam-detail') || document.querySelector('.exam-cnt') || document.body; if (!host) return; let appendix = document.getElementById(PRACTICE_CONTAINER_ID); if (!appendix) { appendix = document.createElement('div'); appendix.id = PRACTICE_CONTAINER_ID; host.appendChild(appendix); } appendix.innerHTML = '
答案
'; document.querySelectorAll('.tk-quest-item').forEach((item, index) => { const answerBlock = item.querySelector('.exam-item__opt') || item.querySelector('.exam-item__analyze'); if (!answerBlock) return; const clone = answerBlock.cloneNode(true); answerBlock.classList.add('ijws-practice-hidden'); const wrapper = document.createElement('div'); wrapper.className = 'ijws-practice-answer'; wrapper.innerHTML = `
第 ${index + 1} 题
`; wrapper.appendChild(clone); appendix.appendChild(wrapper); }); } function buildAnswerOnlyAppendix() { const host = document.querySelector('.page.exam-detail') || document.querySelector('.exam-cnt') || document.body; if (!host) return; let container = document.getElementById(ANSWER_CONTAINER_ID); if (!container) { container = document.createElement('div'); container.id = ANSWER_CONTAINER_ID; host.appendChild(container); } container.innerHTML = '
答案列表
'; // 为答案块补充题号,克隆时一并带入 addQuestionNumbers(); document.querySelectorAll('.tk-quest-item').forEach((item, index) => { const answerBlock = item.querySelector('.exam-item__opt') || item.querySelector('.exam-item__analyze'); if (!answerBlock) return; const clone = answerBlock.cloneNode(true); const wrapper = document.createElement('div'); wrapper.className = 'ijws-answer-item'; wrapper.innerHTML = `
第 ${index + 1} 题
`; wrapper.appendChild(clone); container.appendChild(wrapper); item.dataset.ijwsHiddenByAnswerMode = 'true'; item.style.display = 'none'; }); } function clearAnswerModeArtifacts() { document.querySelectorAll('.tk-quest-item').forEach((item) => { if (item.dataset.ijwsHiddenByAnswerMode === 'true') { item.style.display = ''; delete item.dataset.ijwsHiddenByAnswerMode; } }); const container = document.getElementById(ANSWER_CONTAINER_ID); if (container) { container.remove(); } } function resetReferenceArtifacts() { const showAnswerBtn = document.querySelector('.tklabel-checkbox.show-answer.checkbox-default'); if (showAnswerBtn && showAnswerBtn.classList.contains('checked')) { showAnswerBtn.click(); } removeQuestionNumbers(); } })();