您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
e-typingで継続ノーミス記録を表示する
// ==UserScript== // @name [e-typing]累計コンボ数表示 // @namespace http://tampermonkey.net/ // @version 0.2 // @description e-typingで継続ノーミス記録を表示する // @author xyu // @match https://www.e-typing.ne.jp/* // @icon https://www.google.com/s2/favicons?sz=64&domain=e-typing.ne.jp // @grant none // @license MIT // ==/UserScript== if(localStorage.getItem('totalCombo') == undefined){ localStorage.setItem('totalCombo',0) localStorage.setItem('round',0) localStorage.setItem('averageWPM',0) localStorage.setItem('bestCombo',0) } let clearLineCount = 0 let typingAppModInterval let createOptionInterval let displayComboSwitch let bestCombo = +localStorage.getItem('bestCombo') let totalCombo = +localStorage.getItem("totalCombo") let combo = 0 let wpmCountFlag = true let scoreCheck let typingMode = "roma" let enteredClass = 2 if(location.href.match(/kana\.1/)){ typingMode = "kana" enteredClass = 1 }else if(location.href.match(/std\.2/) || location.href.match(/lstn\.4/)){ typingMode = "eng" enteredClass = 1 }else{ typingMode = "roma" enteredClass = 2 } const createOption = () => { console.log("createOption") const FUNC_VIEW = document.getElementById("func_view") const DISABLE_OPTION = document.getElementById("disable-option") if(FUNC_VIEW){ displayComboSwitch = localStorage.getItem("combo-option") == "false" ? false : true; FUNC_VIEW.style.height = document.getElementById("func_view").clientHeight + 30 + "px" FUNC_VIEW.insertAdjacentHTML('beforeend' , `<div> <div><label><small>累計コンボ数表示</small><input id="combo-option" type="checkbox" style="display:none;" ${displayComboSwitch == false ? "" : "checked"}><div id="combo-btn" style="margin-left:4px;" class="switch_btn"><a class="on_btn btn show">ON</a><a class="off_btn btn" style="display:${displayComboSwitch == false ? "block" : ""};">OFF</a></div></label></div> </div>`) document.getElementById("combo-option").addEventListener("change" , event => { localStorage.setItem("combo-option" , event.target.checked); if(event.target.checked){ document.querySelector("#combo-btn .off_btn").style.display = "" displayComboSwitch = true; }else{ document.querySelector("#combo-btn .off_btn").style.display = "block" displayComboSwitch = false; } }) clearInterval(createOptionInterval) } } const typingAppMod = () => { const example_container = document.getElementById("example_container") //iframe内の要素を取得 if(example_container){ let keyJudge = event => { let sentenceText = document.getElementsByClassName("entered")[enteredClass] if(sentenceText){ sentenceText = document.getElementsByClassName("entered")[enteredClass].nextSibling.textContent let char = windows_keymap[event.code] ? windows_keymap[event.code] : kana_keymap[event.key]; if(!char || (event.key == ' ' && typingMode != "eng")){return;} //正タイプ combo++ updateCombo() if(scoreCheck){ scoreCheck.bestScorePass() } if(sentenceText.length == 1){ //ラインクリア clearLineCount++ } console.log(combo) }else{ const startMsg = document.getElementById("start_msg") const countdown = document.getElementById('countdown') if((startMsg || countdown) && event.key == ' '){ totalCombo = +localStorage.getItem("totalCombo") updateCombo() document.getElementById('total-combo').textContent = totalCombo document.getElementById('round').textContent = localStorage.getItem("round") missScreenObserver() appObserver() wpmCountFlag = true scoreCheck = new ScoreCheck() document.getElementById("wpm-area").classList.add('hide') } } } if(displayComboSwitch){ const width = document.getElementById("example_container").clientWidth const scale = document.getElementById("app").style.webkitTransform.replace(/[^\d^\.]/g,'') document.addEventListener("keydown",keyJudge,false) document.getElementById("ad_frame").style.display = 'none'; document.getElementById("ad_frame").insertAdjacentHTML('beforebegin', `<div id="combo-container" style="width:${width * (scale ? scale:1)}px;"> <span id="combo-area" class="area" title="最高記録:${bestCombo}コンボ"><ruby><span id="total-combo">${totalCombo}</span><rt>累計</rt></ruby> + <ruby><span id="combo">0</span><rt>コンボ</rt></ruby> = <ruby><span id="all-combo" class="${bestCombo < totalCombo ? 'gold' : ''}">${totalCombo}</span><rt>継続</rt></ruby></span> <span id="round-area" class="area"><span id="round">${+localStorage.getItem('round')}</span>周</span> <span id="wpm-area" class="hide area"><ruby><span id="average-wpm_">---</span><rt>平均WPM</rt></ruby></span></div> <style> #combo-container{ margin-left: auto; margin-right: auto; font-weight: bold; font-size: 2rem; margin-top: 2rem; white-space: nowrap; margin-bottom: 2rem; } .area{ padding: 0.2rem 1rem; background: #ff9c0091; border-radius: 23px; } #combo-container > span:not(:first-child){ margin-left:1rem; } #wpm-area{ padding-top:1rem; } #combo-area{ padding-top:1.5rem; } #all-combo{ font-size:2.5rem; } .hide{ visibility: hidden; } .gold{ color: gold; text-shadow: 1px 1px 0px #000, -1px -1px 0px #000, -1px 1px 0px #000, 1px -1px 0px #000, 1px 0px 0px #000, -1px 0px 0px #000, 0px 1px 0px #000, 0px -1px 0px #000; } </style> `) window.addEventListener('beforeunload', () => { if(combo){ updateTotalCombo() updateRoundCount() } }) if(window.parent.document.getElementsByClassName('pp_close').length){ window.parent.document.getElementsByClassName('pp_close')[0].addEventListener('click', () => { updateTotalCombo() updateRoundCount() }) } window.addEventListener('resize',resize) } clearInterval(typingAppModInterval) typingAppModInterval = null } console.log("searching for example_container") } function updateCombo(){ document.getElementById('combo').textContent = combo document.getElementById('all-combo').textContent = totalCombo + combo } function updateTotalCombo(){ localStorage.setItem("totalCombo",+localStorage.getItem("totalCombo") + combo) combo = 0 } class ScoreCheck{ bestScorePass(){ if(bestCombo < (totalCombo + combo)){ document.getElementById('all-combo').classList.add('gold') scoreCheck = null } } } function resetCombo(){ combo = 0 totalCombo = 0 localStorage.setItem("totalCombo",0) } function updateRoundCount(){ let round = +localStorage.getItem('round') round += Math.round((clearLineCount/15) * 10) / 10; localStorage.setItem("round",round) clearLineCount = 0 } function updateAverageWpm(){ setTimeout( () => { if(document.getElementById('result') != null){ const results = document.getElementsByClassName("result_data")[0].firstElementChild.children const aveWpm = +localStorage.getItem('averageWPM') for(let i=0;i<results.length;i++){ if(results[i].firstElementChild.textContent == 'WPM'){ const wpm = +results[i].lastElementChild.textContent putOptionSaveData(wpm) getAllIndexeddbData(wpm) } } }else{ updateAverageWpm() } },100) } function reset(){ if(bestCombo < (totalCombo + combo)){ bestCombo = (totalCombo + combo) localStorage.setItem('bestCombo',totalCombo + combo) document.getElementById('combo-area').title = `最高記録:${bestCombo}コンボ` } document.getElementById('all-combo').classList.remove('gold') resetCombo() updateCombo() clearData() document.getElementById('total-combo').textContent = totalCombo localStorage.setItem("round",0) clearLineCount = 0 document.getElementById('round').textContent = 0 wpmCountFlag = false scoreCheck = new ScoreCheck() } const createEventInTypingApp = (() => { // https://www.e-typing.ne.jp/app/jsa_std/typing.asp タイピング画面のiframe URL if( location.href.match(/app\/jsa_/)){ typingAppModInterval = setInterval(typingAppMod , 50) createOptionInterval = setInterval(createOption , 100) } })() function resize(){ if(document.getElementById("example_container") == null){return;} const width = document.getElementById("example_container").clientWidth const scale = document.getElementById("app").style.webkitTransform.replace(/[^\d^\.]/g,'') document.getElementById('combo-container').style.width = (width * (scale ? scale:1)) + "px" } function missScreenObserver(){ const target = document.getElementById('miss_type_screen'); // body要素を監視 const observer_a = new MutationObserver(function (mutations) { // observer.disconnect(); // 監視を終了 if(combo){ reset() } }); // 監視を開始 observer_a.observe(target, { attributes: true // 属性変化の監視 }); } function appObserver(){ const target = document.getElementById('app'); // body要素を監視 const observer_b = new MutationObserver(function (mutations) { observer_b.disconnect(); // 監視を終了 updateTotalCombo() updateRoundCount() if(wpmCountFlag){ updateAverageWpm() } }); // 監視を開始 observer_b.observe(target, { childList: true }); } let kana_keymap = { 0: ["わ"], 1: ["ぬ"], "!": ["ぬ"], 2: ["ふ"], 3: ["あ"], 4: ["う"], 5: ["え"], 6: ["お"], 7: ["や"], 8: ["ゆ"], 9: ["よ"], "-": ["ほ","-"], "q": ["た"], "Q": ["た"], "w": ["て"], "W": ["て"], "e": ["い"], "E": ["い"], "r": ["す"], "R": ["す"], "t": ["か"], "T": ["か"], "y": ["ん"], "Y": ["ん"], "u": ["な"], "U": ["な"], "i": ["に"], "I": ["に"], "o": ["ら"], "O": ["ら"], "p": ["せ"], "P": ["せ"], "a": ["ち"], "A": ["ち"], "s": ["と"], "S": ["と"], "d": ["し"], "D": ["し"], "f": ["は"], "F": ["は"], "g": ["き"], "G": ["き"], "h": ["く"], "H": ["く"], "j": ["ま"], "J": ["ま"], "k": ["の"], "K": ["の"], "l": ["り"], "L": ["り"], "z": ["つ"], "Z": ["つ"], "x": ["さ"], "X": ["さ"], "c": ["そ"], "C": ["そ"], "v": ["ひ"], "V": ["ひ"], "b": ["こ"], "B": ["こ"], "n": ["み"], "N": ["み"], "m": ["も"], "M": ["も"], ",": ["ね",","], "<": ["、"], ".": ["る","."], ">": ["。"], "/": ["め","/"], "?": ["・"], "#": ["ぁ"], "$": ["ぅ"], "%": ["ぇ"], "'": ["ゃ","’","'"], "^": ["へ"], "~": ["へ"], "&": ["ぉ"], "(": ["ゅ"], ")": ["ょ"], '|': ["ー"], "_": ["ろ"], "=": ["ほ"], "+": ["れ"], ";": ["れ"], '"': ["ふ","”","“","\""], "@": ["゛"], '`': ["゛"], "[": ["゜"], ']': ["む"], "{": ["「"], '}': ["」"], ":": ["け"], "*": ["け"] } let windows_keymap = { 'IntlYen': ["ー","¥","\\"], "IntlRo": ["ろ","¥","\\"], "Space": [" "], "Numpad1": [], "Numpad2": [], "Numpad3": [], "Numpad4": [], "Numpad5": [], "Numpad6": [], "Numpad7": [], "Numpad8": [], "Numpad9": [], "Numpad0": [], "NumpadDivide": [], "NumpadMultiply": [], "NumpadSubtract": [], "NumpadAdd": [], "NumpadDecimal": [] } let db; let indexedDB = window.indexedDB || window.mozIndexedDB || window.msIndexedDB; let OptionDatabaseObject = {} const STORE_NAME = "wpmDB"; const STORE_KEYPATH = ["wpm"]; //filterDBにアクセス (function accessIndexedDB(){ const OPEN_REQUEST = indexedDB.open(STORE_NAME, 1.0); //データベースストア新規作成。(初回アクセス時) OPEN_REQUEST.onupgradeneeded = function(event) { // データベースのバージョンに変更があった場合(初めての場合もここを通ります。) db = event.target.result; const CREATE_filterList = db.createObjectStore("wpm", { keyPath:STORE_KEYPATH[0]}); } //データベースストアアクセス成功時。 OPEN_REQUEST.onsuccess = function(event) { db = event.target.result; } })(); function getAllIndexeddbData(wpm) { //トランザクション var transaction = db.transaction(STORE_KEYPATH, 'readonly'); //オブジェクトストアにアクセスします。 var listObjectStore = transaction.objectStore(STORE_KEYPATH[0]); //全件取得 var listRequest = listObjectStore.getAllKeys() //取得が成功した場合の関数宣言 listRequest.onsuccess = function (event) { const result = event.currentTarget.result let sum = result.reduce(function (acc, cur) { return acc + cur; }); document.getElementById("average-wpm_").textContent = ((sum+wpm) / (result.length+1)).toFixed(2) document.getElementById("wpm-area").classList.remove('hide') }; } //データを保存 function putOptionSaveData(Data){ const SEND_DATA = {[STORE_KEYPATH[0]] : Data}; const OPEN_REQ = window.indexedDB.open(STORE_NAME); OPEN_REQ.onsuccess = function(event){ var db = event.target.result; var trans = db.transaction(STORE_KEYPATH[0], 'readwrite'); var store = trans.objectStore(STORE_KEYPATH[0]); var putReq = store.put(SEND_DATA); } } //削除 function clearData() { // open a read/write db transaction, ready for clearing the data const transaction = db.transaction(STORE_KEYPATH, "readwrite"); // create an object store on the transaction const objectStore = transaction.objectStore(STORE_KEYPATH[0]); // Make a request to clear all the data out of the object store const objectStoreRequest = objectStore.clear(); objectStoreRequest.onsuccess = (event) => { // report the success of our request }; };
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址