// ==UserScript== // @name Bunpro: wanakana workaround // @description Restores the cursor position after wanakana conversion // @version 0.1 // @namespace https://pampel.dev // @run-at document-start // @author pampel // @match https://bunpro.jp/* // @grant none // @downloadURL none // ==/UserScript== 'use strict'; addEventListener("turbolinks:load", () => { let inputElem = document.querySelector("#study-answer-input"); if (!inputElem) return; let oldEndPos = 0; inputElem.addEventListener('keydown', e => { switch (e.key) { case 'ArrowLeft': oldEndPos = Math.max(oldEndPos - 1, 0); break; case 'ArrowRight': oldEndPos = Math.min(oldEndPos + 1, inputElem.value.length); break; case 'Home': case 'PageUp': case 'ArrowUp': oldEndPos = 0; break; case 'End': case 'PageDown': case 'ArrowDown': oldEndPos = inputElem.value.length; break; } }); let vocals = ["a", "e", "i", "o", "u"]; let oldLength = 0; // firefox version inputElem.addEventListener('selectionchange', e => { setTimeout(() => { if (inputElem.selectionEnd === inputElem.value.length && inputElem.selectionStart === inputElem.selectionEnd) { let newEndPos = inputElem.value.length - oldLength + oldEndPos; // the selectionchange event is fired on selectionEnd assignment even if the value doesn't change // so without this condition the event is fired constantly when the cursor is at the of the input field if (inputElem.selectionEnd !== newEndPos) inputElem.selectionEnd = newEndPos; } oldEndPos = inputElem.selectionEnd; oldLength = inputElem.value.length; }, 0); }); // chrome version document.addEventListener('selectionchange', e => { if (document.activeElement !== inputElem) return; if (inputElem.selectionEnd === inputElem.value.length && inputElem.selectionStart === inputElem.selectionEnd) inputElem.selectionEnd = inputElem.value.length - oldLength + oldEndPos; oldEndPos = inputElem.selectionEnd; oldLength = inputElem.value.length; }); });