Thanks @BlackBeans for caring about my digital wellbeing, but I don’t really mind the pinging
It’s an honor some people reach out to me for help - altough I don’t always find the time for it.
@huyvanphan, try this script for your front template of “Basic (type in the answer)”:
<script>
(() => {
/**
* Type-in-the-answer live feedback for Anki
* @author Matthias Metelka | @kleinerpirat
*/
/* Helper functions to keep caret position while typing */
const getCaretPosition = (contenteditable) => {
contenteditable.focus();
let _range = document.getSelection().getRangeAt(0);
let range = _range.cloneRange();
range.selectNodeContents(contenteditable);
range.setEnd(_range.endContainer, _range.endOffset);
return range.toString().length;
};
const setCaretPosition = (contenteditable, pos) => {
contenteditable.focus();
document.getSelection().collapse(contenteditable, pos);
};
/* Replace input with contenteditable div */
const input = document.getElementById("typeans");
const editable = document.createElement("div");
editable.contentEditable = true;
editable.id = "typeans";
editable.innerHTML = input.value;
input.replaceWith(editable);
editable.addEventListener("input", () => {
const pos = getCaretPosition(editable);
/* Anki uses value attribute to compare answer */
editable.value = editable.innerText;
editable.innerHTML = (() => {
const letters = editable.innerText.split("");
const word = "{{Answer}}";
let html = "";
letters.forEach((letter, i) => {
html += `<span class="${
letter == word[i] ? "typeGood" : "typeBad"
}">${letter}</span>`;
});
return html;
})();
setCaretPosition(editable, pos);
});
})();
</script>
CSS
[contenteditable]#typeans {
border: thin solid var(--border);
background: var(--frame-bg);
}
Explanation
Anki uses an input element for its answer box, which cannot contain HTML, only plain text - so it can’t be styled. My script replaces that input element with a contenteditable (the same kind of element that’s used for the fields in Anki’s note editor).
I wrap each letter in its own <span>, using Anki’s classes “typeGood” and “typeBad” for color-coding.
There’s some overhead because updating the inner HTML of such an element moves the caret position to the start.