How to create advanced anki hint script

hey guys,

I was wondering if this is possible?

Lets say you have one field which is a sentence and another field which has a word from that sentence
The script would activate on keydown of a specific key which would show you the sentence field minus the word from the other field

Example:
Field one: A tomato is a type of vegetable
Field two: vegetable
Java script hint: A tomato is a type of

I realise that this is exactly what cloze deletion cards do but for my purpose I really need this as a java script

@kleinerpirat

Just to be clear, what you are asking for is the following (taking your example):

  • During review, I see “A tomato is a type of vegetable”;
  • If I can’t find “vegetable”, I click on, say, P;
  • The sentence becomes something like “A tomato is a type of […]”.

Or

  • During review, I directly see “A tomato is a type of […]”.

Hi @BlackBeans

I’m asking for the first option. Do you think its possible?

It’s certainly feasible, and actually not that hard. However, words of warning have to be spoken before you are given that power: if you make it easier for you to find the word you have to memorize with hints, you’re not going to remember them well. In fact, you might start learning these relying specifically on that hint, and you may not remember them at all in a real conversation, say. This is because your brain is “lazy” (or “smart”, depending on how you see it), and it will take anything it can to help it memorize a word. If you always provide it a hint, it will just get used to it, because there is no need not to do so, and because it’s probably easier to give the good answer with the hint than without it. And Anki won’t help you there: if you say you didn’t remember the word, Anki will take that into account, but if you didn’t remember, clicked on the hint, and then found the word, you’ll say you remembered, so Anki will just process that as if you remembered perfectly the word, although you didn’t.
Are you sure you really want what you asked for?

Besides that, there is a difference between a Java script and a JavaScript script, and what you want is the latter, not the former.

1 Like

awesome! yes I’m sure I want that haha. I understand your reasoning regarding hints and I agree to an extent although I think hints can be useful when used on difficult cards.

I certainly agree that if the hint is the answer to the card like in my example it’s not a good idea.

You could do it like this:

Front

<div id="word">{{Word}}</div>
<div id="sentence" hidden>{{Sentence}}</div>
<div id="sentenceHint" hidden>Press <kbd>P</kbd> to show hint</div>

<script>
  setTimeout(() => {
    const hint = document.getElementById("sentenceHint");
    hint.removeAttribute("hidden");

    if (!globalThis.fakeClozeListening) {
      document.addEventListener("keydown", (e) => {
        if (e.code == "KeyP") {
          const word = document.getElementById("word").innerText;
          const sentence = document.getElementById("sentence").innerHTML;

          hint.innerHTML = sentence.replace(
            new RegExp(`${word}`, "gi"), "[...]"
          );
        }
      });
      globalThis.fakeClozeListening = true;
    }
  }, 5000);
</script>

Edit 1: Sorry I missed the part where you want to reveal on keydown. I’ll edit this post in a few minutes.


EDIT 2: Okay, I edited the script to fit option 1 in @BlackBeans post. Initially, I thought you just want regular cloze functionality. The replacement is case-insensitive, but it won’t work for declinations of that word (for obvious reasons).

I added a time delay of 5s until the hint can be shown. You can of course remove that from the script or make it shorter. When deleting, just make sure to replace setTimeout with an IIFE like

(() => { CODE })();

or just remove , 5000 or replace it with 0.

2 Likes

Thank you - looking forward to your edit and trying it out :smiley:

wow exactly what I wanted! Works amazingly - Thank you so much! You’re really talented!

1 Like

When I put this script above a separate {{hint:Hint}} in Anki, when I press the keydown it removes the hint below. But when I put the script below the {{hint:Hint}} it doesnt remove the hint. Im guessing it has something to do with the amount of lines that the script uses and it probably overrides content below it? Would there be an easy fix to this? It’s not a big deal as I don’t mind keeping the script below other hints.

Ah, this sounds like hint is reserved by Anki. Try replacing the two occurences of that id with something else, like sentenceHint.

Edit: sorry, no, there was a mistake in my script. I’ve updated it again.

Hi I tried the new script. It still removes all {{hint:}} underneath the script when I press P
I’m not sure what could be causing it as it doesn’t happen with the other script you made

Would you please show me your front template? I cannot reproduce the issue.

<div id="word"hidden>{{Word}}</div>
<div id="sentence" hidden>{{Sentence}}</div>
<div id="sentenceHint"</div>

<script>
  setTimeout(() => {
    const hint = document.getElementById("sentenceHint");
    hint.removeAttribute("hidden");

    if (!globalThis.fakeClozeListening) {
      document.addEventListener("keydown", (e) => {
        if (e.code == "F11") {
          const word = document.getElementById("word").innerText;
          const sentence = document.getElementById("sentence").innerHTML;

          hint.innerHTML = sentence.replace(
            new RegExp(`${word}`, "gi"), "[...]"
          );
        }
      });
      globalThis.fakeClozeListening = true;
    }
  }, 0);
</script>

<br><br>
{{hint:Word}}
{{hint:Sentence}}`

You had some invalid HTML syntax going on. I saw you removed the delay as well as the notification for the shortcut, so here’s a modified version:

<div id="word">{{Word}}</div>
<div id="sentence" hidden>{{Sentence}}</div>
<div id="clozeHint"></div>

<div>{{hint:Word}}</div>
<div>{{hint:Sentence}}</div>

<script>
  (function clozeHint() {
    const hint = document.getElementById("clozeHint");

    if (!globalThis.clozeHintListening) {
      document.addEventListener("keydown", (e) => {
        if (e.code == "F11") {
          const word = document.getElementById("word").innerText;
          const sentence = document.getElementById("sentence").innerHTML;

          hint.innerHTML = sentence.replace(
            new RegExp(`${word}`, "gi"), "[...]"
          );
        }
      });
      globalThis.clozeHintListening = true;
    }
  })();
</script>

It will work regardless of the script position, but I would still recommend to put scripts below all of your other HTML.


Instead of <br><br> you can give the divs a margin using CSS:

div:not(:first-of-type) {
  margin-top: 1em;
}
2 Likes

The script works in preview mode and the first card I study but then it doesn’t work anymore.

Would you know any fix to this issue?

1 Like
  (function clozeHint() {
--  const hint = document.getElementById("clozeHint");

    if (!globalThis.clozeHintListening) {
      document.addEventListener("keydown", (e) => {
        if (e.code == "F11") {
          const word = document.getElementById("word").innerText;
          const sentence = document.getElementById("sentence").innerHTML;
++        const hint = document.getElementById("clozeHint");

          hint.innerHTML = sentence.replace(
            new RegExp(`${word}`, "gi"), "[...]"
          );
        }
      });
      globalThis.clozeHintListening = true;
    }
  })();

Moving that const declaration into the EventListener callback should fix the issue. That was an oversight on my part, thanks for testing.

If you’re interested why: The EventListener is only attached to the document once, because I set up a guard with globalThis.clozeHintListening. The node assigned to const hint only exists on the first card - afterwards its parent node is refreshed, therefore the reference points nowhere anymore.
By moving the declaration down into the EventListener’s callback function, it will execute every time you press the specified key.


How are you faring with the shortcut F11? Doesn’t this interfere with Anki’s fullscreen toggle?

1 Like

Thanks for the explanation. Im interesting in learning this stuff but dont know where to start. how did you get so good?

The script now works perfectly :smiley: Thanks! F11 is not an issue as im using an old anki version 2.1.22 which doesnt have full screen I think

Before I switched to medicine, I studied CS at university for two years. Don’t let that discourage you, for the frontend stuff I’m doing with Anki, I don’t need a fraction of what I had to learn there. The only really useful parts of the curriculum were the basics of the tech behind computers and certain programming paradigms.

I would recommend you search a course that teaches the absolute basics of computer science. For example, Harvard University offers a very popular free course called CS50 for free on edX, where you can familiarize yourself with multiple languages (C, Python, SQL, and JavaScript plus CSS and HTML).

Then, once you got the basic ideas of programs (logic, loops, declarations/assignments, etc.), try to realize simple Anki ideas on your own. Anki is the perfect playground for aspiring developers. It uses a diverse set of languages and as an open source project, it also motivates you to learn Git. I’d estimate I’ve learned ~90% of my current skillset autodidactically while working on Anki templates, add-ons or the source code itself.

2 Likes

wow thanks, ill check out that course and try to learn the fundamentals! :smiley:

Really appreciate the time and effort you spent helping me!