您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Forces kids to submit what they have typed for words they dont know how to spell, and lets Quizlet correct their spelling. Includes a short configurable break and an alarm to get them to come back when the break ends.
当前为
// ==UserScript== // @name Quizlet Spell Autosubmit timer. // @version 0.0.1 // @grant none // @match https://quizlet.com/*/spell // @description Forces kids to submit what they have typed for words they dont know how to spell, and lets Quizlet correct their spelling. Includes a short configurable break and an alarm to get them to come back when the break ends. // @namespace https://gf.qytechs.cn/users/82098 // ==/UserScript== /* * This is a JavaScript Scratchpad. * * Enter some JavaScript, then Right Click or choose from the Execute Menu: * 1. Run to evaluate the selected text (Ctrl+R), * 2. Inspect to bring up an Object Inspector on the result (Ctrl+I), or, * 3. Display to insert the result in a comment after the selection. (Ctrl+L) */ function getElementByXpath(path,node=document) { return document.evaluate(path, node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } function XPath(xpath) { if (!( this instanceof XPath) ) { return new XPath(xpath); } var self = this; self.xpath=xpath; self.contains = function(attr,text) { self.xpath += "contains(concat(' ', normalize-space(" + attr + "), ' '), ' " + text + " ')"; return self; }; self.append = function(text) { self.xpath += text; return self; }; self.as_text = function() { return self.xpath; }; self.fetch = function(node=document) { return getElementByXpath(self.xpath,node); }; return self; } function CountdownElm(attr={}) { if (!( this instanceof CountdownElm) ) { return new CountdownElm(attr); } var elm=attr.elm; var endtime=attr.endtime; var paused_remainingtime=0; var is_paused = false; var should_reset_time = false; this.updateUI=function() { var r = Math.floor(this.remainingtime/1000 + 0.5); r = Math.max(r,0); elm.innerHTML=Math.floor(this.remainingtime/1000 + 0.5); }; this.pause = function() { if (!is_paused) { paused_remainingtime = this.remainingtime; is_paused = true; should_reset_time = true; } }; this.unpause = function() { if (is_paused) { this.endtime_from_millisec(paused_remainingtime); paused_remainingtime=0; is_paused=false; should_reset_time = false; } }; this.endtime_from_millisec = function(milli) { endtime = new Date().getTime() + milli; should_reset_time = false; }; Object.defineProperties(this,{ endtime: { get: function() { return endtime; }, set: function(val) { endtime = val; should_reset_time = false; this.updateUI(); }, }, remainingtime: { get: function() { if (!is_paused) { return endtime - new Date().getTime(); } else { return paused_remainingtime; } } } }); return this; } function QuizletSpellTimer(initargs={}) { if (!( this instanceof QuizletSpellTimer) ) { return new QuizletSpellTimer(initArgs); } var qst = this; function Print(msg) { console.log(msg); } function toSeconds(hms) { // HH:MM:SS to seconds var a = hms.split(':'); // split it at the colons // minutes are worth 60 seconds. Hours are worth 60 minutes. return (+a[0]) * 60 * 60 + (+a[1]) * 60 + (+a[2]); } function htmlToElement(html) { var template = document.createElement('template'); html = html.trim(); // Never return a text node of whitespace as the result template.innerHTML = html; return template.content.firstChild; } function isHidden(el) { return (el.offsetParent === null) } function CheckLoop(xpath,fn,cnt=50,delay=100) { if (getElementByXpath(xpath)) { fn(); } else if (cnt != 0) { setTimeout(function() { CheckLoop(cnt - 1); },delay); } else { Print("Failed to find xpath '" + xpath + "'"); } } const keycodes={ backspace:8, tab:9, enter:13, shift:16, ctrl:17, alt:18, pause_break:19, capslock:20, escape:27, space:32, pageup:33, pagedown:34, end:35, home:36, leftarrow:37, uparrow:38, rightarrow:39, downarrow:40, insert:45, delete:46, 0:48, 1:49, 2:50, 3:51, 4:52, 5:53, 6:54, 7:55, 8:56, 9:57, a:65, b:66, c:67, d:68, e:69, f:70, g:71, h:72, i:73, j:74, k:75, l:76, m:77, n:78, o:79, p:80, q:81, r:82, s:83, t:84, u:85, v:86, w:87, x:88, y:89, z:90, multiply: 106, add: 107, subtract: 109, decimalpoint: 110, divide: 111, f1: 112, f2: 113, f3: 114, f4: 115, f5: 116, f6: 117, f7: 118, f8: 119, f9: 120, f10: 121, f11: 122, f12: 123, numlock: 144, scrolllock: 145, semicolon: 186, equalsign: 187, comma: 188, dash: 189, period: 190, forwardslash: 191, graveaccent: 192, openbracket: 219, backslash: 220, closebraket: 221, singlequote: 222 }; const enter_keyboard_event = new KeyboardEvent('keydown',{'keyCode':keycodes.enter,'which':keycodes.enter}); const GameState = { Spelling: 0, ReviewingMisspelled: 1, Break: 2, BreakOver: 3, Paused: 4, }; var progress_cont_xp = new XPath("//div[").contains("@class","ModeControls-progress").append("]"); var break_countdown_cont = htmlToElement(`<div class='ModeControls-progressSection'> <h4 id="break_tite">Next Break</h4> <br> <h5 id="break_time">0</h5> </div>`); var spell_countdown_cont = htmlToElement(`<div class='ModeControls-progressSection'> <h4 id="spell_tite">Give Up In</h4> <br> <h5 id="spell_time">0</h5> </div>`); var pause_button_cont = htmlToElement(`<div class='ModeControls-progressSection'> <button class="h1" id="pause_play">Play</button> </div>`); var paused_overlay = htmlToElement(`<div style="z-index: 100; background-color: #000; height: 100%; width: 100%; position: absolute; top:0; left:0; display:none; "> </div>`); this.settings = { per_letter_time: 5, max_spell_time: 30, loop_timeout: 300, break: { length: toSeconds("00:05:00"), delay: toSeconds("00:15:00"), }, sounds: { break_over: '', }, }; this.audio = new Audio(this.settings.sounds.break_over); this.elm = {}; this.state = {}; this.is_initialized=false; this.ctime=new Date().getTime(); this.pause = { max_pause_cnt: 2, pause_history_durration: toSeconds("00:05:00"), pause_hist: [], can_pause: function() { var pause_cnt = 0; for (const pause of qst.pause.pause_hist ) { if (pause >= (qst.ctime - (qst.pause.pause_history_durration * 1000)) ) { pause_cnt += 1; } } return pause_cnt < qst.pause.max_pause_cnt; }, try_pause: function() { if (qst.pause.can_pause()) { qst.pause.pause_hist.push(qst.ctime); qst.pause.pause_hist.splice(0,qst.pause.pause_hist.length - qst.pause.max_pause_cnt); return true; } return false; } } this.gamestate= GameState.Spelling; function initNewWord() { qst.start_time=new Date().getTime(); qst.state.spell_countdown.unpause(); qst.state.break_countdown.unpause(); qst.state.spell_countdown.endtime_from_millisec(qst.settings.max_spell_time * 1000); } function onSpellTimeout() { qst.elm.spelling_box.dispatchEvent(enter_keyboard_event); qst.gamestate=GameState.ReviewingMisspelled; qst.state.spell_countdown.pause(); qst.state.break_countdown.pause(); } function onPause() { qst.gamestate = GameState.Paused; paused_overlay.style.display="inline"; qst.state.spell_countdown.pause(); qst.state.break_countdown.pause(); } function onResume() { qst.gamestate = GameState.Spelling; paused_overlay.style.display="inline"; qst.state.spell_countdown.unpause(); qst.state.break_countdown.unpause(); } function onPausePlay() { if (qst.gamestate == GameState.Paused || qst.gamestate == GameState.BreakOver ) { onResume(); } else if (qst.gamestate == GameState.Spelling || qst.gamestate == GameState.ReviewingMisspelled ) { if (qst.pause.try_pause()) { onPause(); } } } function updatePausePlay() { if (qst.gamestate == GameState.Paused || qst.gamestate == GameState.BreakOver ) { qst.elm.pauseplay_button.textContent="Play"; } else if (qst.gamestate == GameState.Spelling || qst.gamestate == GameState.ReviewingMisspelled ) { qst.elm.pauseplay_button.textContent="Pause"; qst.elm.pauseplay_button.disabled=!qst.pause.can_pause(); } } function onBreak() { onPause(); qst.gamestate=GameState.Break; qst.state.break_countdown.endtime_from_millisec(qst.settings.break.length * 1000); } function MainLoop() { qst.ctime=new Date().getTime(); var ctimeout = qst.settings.loop_timeout; if (qst.gamestate == GameState.Spelling) { paused_overlay.style.display="none"; if (qst.state.break_countdown.remainingtime <= 0) { onBreak(); } if (qst.state.spell_countdown.remainingtime <= 0) { onSpellTimeout(); ctimeout = 1300; // Give time for menu to hide } } else if (qst.gamestate == GameState.ReviewingMisspelled) { Print("Reviewing"); if (!isHidden(qst.elm.spelling_box)) { Print("Done"); initNewWord(); qst.gamestate=GameState.Spelling; } else { Print("Not Done"); } } else if (qst.gamestate == GameState.Break) { if (qst.state.break_countdown.remainingtime <= 0) { qst.gamestate == GameState.BreakOver; qst.audio.play(); } } else if (qst.gamestate == GameState.BreakOver) { qst.gamestate=GameState.Spelling; qst.state.break_countdown.endtime_from_millisec(qst.settings.break.delay * 1000); initNewWord(); // Lets give them a full word's worth of time } qst.state.spell_countdown.updateUI(); qst.state.break_countdown.updateUI(); updatePausePlay(); setTimeout(MainLoop,ctimeout); } // NOTE: Game.curTerm.getRawWord() -> Current term string. function Init() { var spell_cont = XPath("//div[@id='SpellModeTarget']").fetch(); paused_overlay.style.backgroundColor="#c9ceeb"; XPath("//div[").contains("@class","ModeLayout-content").append("]").fetch(spell_cont).appendChild(paused_overlay); qst.elm.spelling_box= new XPath("//div[").contains("@class","UITextarea-content").append("]//textarea").fetch(); qst.progress_container = progress_cont_xp.fetch(); qst.progress_container.appendChild(break_countdown_cont); qst.progress_container.appendChild(spell_countdown_cont); qst.progress_container.appendChild(pause_button_cont); qst.elm.break_countdown = new XPath("//*[@id='break_time']").fetch(break_countdown_cont); qst.elm.spell_countdown = new XPath("//*[@id='spell_time']").fetch(spell_countdown_cont); qst.elm.pauseplay_button = new XPath("//*[@id='pause_play']").fetch(pause_button_cont); qst.state={ spell_countdown: CountdownElm({ elm: qst.elm.spell_countdown, endtime: 0, }), break_countdown: CountdownElm({ elm: qst.elm.break_countdown, endtime: 0, }), }; qst.elm.pauseplay_button.onclick=onPausePlay; qst.state.break_countdown.endtime_from_millisec(qst.settings.break.delay * 1000); initNewWord(); MainLoop(); } this.run=function() { CheckLoop(progress_cont_xp.as_text(), Init); }; return this; } var qst = new QuizletSpellTimer(); qst.run();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址