kanji koohii FORUM
Anki Javascript help (randomly select a kanji from between 2-5 choices...) - Printable Version

+- kanji koohii FORUM (http://forum.koohii.com)
+-- Forum: Learning Japanese (http://forum.koohii.com/forum-4.html)
+--- Forum: General discussion (http://forum.koohii.com/forum-8.html)
+--- Thread: Anki Javascript help (randomly select a kanji from between 2-5 choices...) (/thread-13525.html)



Anki Javascript help (randomly select a kanji from between 2-5 choices...) - yogert909 - 2016-01-12

Wondering if anyone can help with some javascript that randomly selects a kanji from between 2-5 choices and remembers the index for the back side.  

I'm making a deck of lookalike kanji from this list courtesy of lauri ranta.  I have 10 fields: Kanji1, Keyword1, Kanji2....and so on up to Keyword5.  I would like to create a javascript that randomly chooses a kanji from the available choices (varies from 2-5 kanji because some are blank).  I'll also show all of the keywords for that group to make kind of a multiple choice card but I don't need javascript for that part.  Then, on the answer side it will show the same info, but with the correct keyword highlighted.

I was looking at this page and trying to adapt the code, but then I noticed it doesn't even do what it claims to do unmodified on my computer.  I did notice a slight error in the 3rd line where } is missing so there may be other errors preventing the javascript from working correctly, or it may be that I'm on a mac, or something else.  I'm also not sure if javascript works on ankimobile which is where I intend to study this deck.

Can anyone point me in the right direction?  I've only used javascript to automate things within another program, but never in combination with css or webpages like most people. If I can get something suitable, I'll post the results so that others can use it too.


RE: Anki Javascript help - Vempele - 2016-01-12

I think js only works on desktop Anki (and even then it's not supported, it just works).

Kanji field: 一二三
Keywords field:  one;two;three

Front:

Code:
<div id="question"></div>
<script>
if (!document.getElementById("answer")) {
   arr = "{{Kanji}}";
   index = Math.floor(Math.random() * arr.length);
   kanji = arr[index];
}
document.getElementById("question").innerText = kanji;
</script>

Back:

Code:
{{FrontSide}}
<hr id=answer>
<div id="result"></div>
<script>
document.getElementById("result").innerText = "{{Keywords}}".split(";")[index];
</script>



RE: Anki Javascript help - yogert909 - 2016-01-12

Hmmm.  I think I did everything right but I'm just getting a horizontal line.  Maybe it's just my mac running an antiquated os.  I'm waiting for the new macs to come out before I upgrade...  Huge thanks anyway.

[Image: QZ5OUcb.png]
[Image: 04PdBSZ.png]


RE: Anki Javascript help - Vempele - 2016-01-12

Looks the same as here, except mine works (on Windows) - though the preview is still incorrect, in a different manner (which would be an example of "works, but unsupported"). https://www.dropbox.com/s/7muqwlz8l8puvwe/MultiKanji.apkg?dl=1


RE: Anki Javascript help - r3ftch - 2016-01-12

In the back Template try to change this
Code:
<hr id=answer>

to this

Code:
<id=answer>

to remove the line


RE: Anki Javascript help - トリピー♫ - 2016-01-12

If you haven't yet, try actually studying the card even thought it looks blank in the preview.
I tried want Vempele posted and it worked fine for me on Windows.
However as he said, the program seems to handle things a little differently in the preview and the actual study screen. It probably won't work, but it's worth a quick shot.

Also, you might test to see if javascript works at all on a Mac by just deleting everything out of the back template and putting the below code in the front. It should put "Hello!" on the front of the card.
Code:
<div id="test"></div>
<script>
document.getElementById("test").innerText = "Hello!";
</script>



RE: Anki Javascript help - yogert909 - 2016-01-13

I don't know what happened, but I opened the deck Vempele posted and that's working as advertised.  It appears to be the exact same code so I don't know what's going on unless there's some invisible styling that came over when I copy/pasted the code last night.  Whatever it is, it's working now, so I should be able to adapt it to my needs.

Thanks for taking time to help me sort this out.

Update: I just tied it on my iPhone and it works! This is great because I'll probably be using it more. Thanks again for the help!!


RE: Anki Javascript help - polyturn - 2016-01-17

(2016-01-12, 6:24 am)yogert909 Wrote: I was looking at this page and trying to adapt the code, but then I noticed it doesn't even do what it claims to do unmodified on my computer.  I did notice a slight error in the 3rd line where } is missing so there may be other errors preventing the javascript from working correctly, or it may be that I'm on a mac, or something else.  I'm also not sure if javascript works on ankimobile which is where I intend to study this deck.

The idea is godsend, I've been looking everywhere for something like this.
Any help please? I'd be eternally grateful if someone could make this work.

Related: http://postimg.org/image/s1f1fooqr/
[Image: full]

The code for the front template is strange though. How was it doing the cloze deletion replacements when the field for the grammatical concept wasn't even scanned?

Here's an example btw of a javascript doing replacements based on a field, I'm sure it'd work for this too but the problem is how to randomize the example sentences. Should I create a new thread for this?

-------------
EDIT:
I've found one of his errors (for the cloze deletion replacement at least)
Code:
<div class="example" id="ex1">
  <span class="jp">{{ex1_jp}}</span><br />
  <span class="jp">{{ex1_en}</span></div>
<div class="example" id="ex1">
  <span class="jp">{{ex2_jp}}</span><br />
  <span class="jp">{{ex2_en}}</span></div>

Should be

Code:
<div class="example" id="ex1">
  <span class="jp">{{ex1_jp}}</span><br />
  <span class="jp">{{ex1_en}</span></div>
<div class="example" id="ex2">
  <span class="jp">{{ex2_jp}}</span><br />
  <span class="jp">{{ex2_en}}</span></div>

otherwise it won't count ex2 (the second div class when the for loop increments)
var exFields = 2; should also be changed to whatever number of example sentences there are.

Can't get to the sentences to randomize though.


RE: Anki Javascript help - トリピー♫ - 2016-01-17

There must be some html in the sentence field. For example, the filed {{ex1_jp}} could contain:
天気予報<span class="cloze">によると</span>明日は雪だ。

That way the javascript would see the elements with class=cloze, get the length of those elements and replace each character with circles. It should work even if you wanted two cloze elements in one sentence. For example:
彼は犬<span class="cloze">のほうが</span>猫<span class="cloze">より</span>好きだ。


RE: Anki Javascript help - トリピー♫ - 2016-01-17

Give this a go.
It will pick a random sentence from however many sentences you have without the need to create a new field for each sentence. Instead of creating a bunch of fields, all the example sentences are put into one field, separated by a vertical bar ("|") since it's unlikely to appear in any sentences.

It will also replace any characters between "cloze" tags with circles on the front of the card.

Keep in mind that this will not work in the preview windows, you actually have to study the card.

The sentences_jp text has to be put in through the "Edit HTML" option (press Ctrl+Shift+X in the sentences_jp field).

Fields:
sentences_jp Wrote:天気予報<cloze>によると</cloze>明日は雪だ。|今日の新聞<cloze>によると</cloze>、また台風がやってくるそうだ。|最近の調査<cloze>によると</cloze>喫煙者の数は減少しつつある。
sentences_en Wrote:According to the weather report, it will rain tomorrow.|According to today's newspaper, another typhoon is coming.|According to a recent survey, the number of smokers is decreasing.
grammar Wrote:~によると - according to

Card Template:
Front Template Wrote:<div id="ex_jp"></div>
<div id="ex_en"></div>
<script>
  var sentences_jp = "{{sentences_jp}}".split("|"); //creates array of J sentences
  var sentences_en = "{{sentences_en}}".split("|"); //creates array of E sentences
  random = Math.floor(sentences_jp.length*Math.random()); //picks a random number

  document.getElementById("ex_jp").innerHTML = sentences_jp[random]; //puts J sentence on screen
  document.getElementById("ex_en").innerHTML = sentences_en[random]; //puts E sentence on screen

  var clozes = document.getElementsByTagName("cloze"); //creates array of all "cloze" elements
  for(var i=0;i<clozes.length;i++){ //loops through all "cloze" elements
     var blankSpace = ""; //creates empty string to replace "cloze" contents
     for (var j=0;j<clozes[i].innerText.length;j++){ //counts through each character in "cloze elements"
       blankSpace += "◯"; //adds one circle for each character in "cloze" element
     }
     clozes[i].innerText = blankSpace; //replaces "cloze" content with circles
  }
</script>
Styling Wrote:.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
cloze{
color: blue;
}
Back Template Wrote:<div id="ex_jp"></div>
<div id="ex_en"></div>
<script>
  document.getElementById("ex_jp").innerHTML = sentences_jp[random];
  document.getElementById("ex_en").innerHTML = sentences_en[random];
</script>
<hr id=answer>
{{grammar}}



RE: Anki Javascript help - polyturn - 2016-01-18

Hm.... Quite nice however I'd still honestly prefer a code that randomizes based on fields, that's because I always include automatically generated sentence glosses per japanese sentence field, If I'd gloss that single field, the gloss field would be too long.

Any chance you could make it work?


RE: Anki Javascript help - トリピー♫ - 2016-01-18

In this example my sentence fields are sentence1_jp, sentence2_jp, etc. And sentence1_en, sentence2_en, etc.

Use the same code as above but replace this:
Code:
 
var sentences_jp = "{{sentences_jp}}".split("|"); //creates array of J sentences
var sentences_en = "{{sentences_en}}".split("|"); //creates array of E sentences


with this:
Code:
 
var sentences_jp = []; //creates empty array for J sentences
var sentences_en = []; //creates empty array for E sentences

sentences_jp.push("{{sentence1_jp}}"); //adds J sentences to array
sentences_jp.push("{{sentence2_jp}}");
sentences_jp.push("{{sentence3_jp}}"); //you need to do this for each field

sentences_en.push("{{sentence1_en}}"); //adds E sentences to array
sentences_en.push("{{sentence2_en}}");
sentences_en.push("{{sentence3_en}}"); //you need to do this for each field

for (var k=0;k<sentences_jp.length;k++){ //loops through J sentence array
   if (sentences_jp[k] == ""){ //checks if field is empty
      sentences_jp.splice(k,1); //removes empty fields from array
   }
}



RE: Anki Javascript help - polyturn - 2016-01-18

http://www.mediafire.com/download/rig3pdipq9gmz6m/DOJG.apkg

Not sure where I went wrong....

Code:
<div id="ex_jp"></div>
<div id="ex_en"></div>
<script>
    var examples_jp = []; //creates empty array for J sentences
    var examples_en = []; //creates empty array for E sentences

    examples_jp.push("{{example 1_jp}}"); //adds J sentences to array
    examples_jp.push("{{example 2_jp}}");
    examples_jp.push("{{example 3_jp}}");
    examples_jp.push("{{example 4_jp}}");
    examples_jp.push("{{example 5_jp}}");
    examples_jp.push("{{example 6_jp}}");
    examples_jp.push("{{example 7_jp}}");
    examples_jp.push("{{example 8_jp}}");
    examples_jp.push("{{example 9_jp}}");
    examples_jp.push("{{example 10_jp}}");
    examples_jp.push("{{example 11_jp}}");
    examples_jp.push("{{example 12_jp}}");
    examples_jp.push("{{example 13_jp}}");
    examples_jp.push("{{example 14_jp}}");
    examples_jp.push("{{example 15_jp}}");
    
    examples_en.push("{{example 1_en}}"); //adds E sentences to array
    examples_en.push("{{example 2_en}}");
    examples_en.push("{{example 3_en}}");
    examples_en.push("{{example 4_en}}");
    examples_en.push("{{example 5_en}}");
    examples_en.push("{{example 6_en}}");
    examples_en.push("{{example 7_en}}");
    examples_en.push("{{example 8_en}}");
    examples_en.push("{{example 9_en}}");
    examples_en.push("{{example 10_en}}");
    examples_en.push("{{example 11_en}}");
    examples_en.push("{{example 12_en}}");
    examples_en.push("{{example 13_en}}");
    examples_en.push("{{example 14_en}}");
    examples_en.push("{{example 15_en}}");

    for (var k=0;k<examples_jp.length;k++){ //loops through J sentence array
       if (examples_jp[k] == ""){ //checks if field is empty
          examples_jp.splice(k,1); //removes empty fields from array
       }
    }
 random = Math.floor(examples_jp.length*Math.random()); //picks a random number

 document.getElementById("ex_jp").innerHTML = examples_jp[random]; //puts J sentence on screen
 document.getElementById("ex_en").innerHTML = examples_en[random]; //puts E sentence on screen

 var clozes = document.getElementsByTagName("cloze"); //creates array of all "cloze" elements
 for(var i=0;i<clozes.length;i++){ //loops through all "cloze" elements
    var blankSpace = ""; //creates empty string to replace "cloze" contents
    for (var j=0;j<clozes[i].innerText.length;j++){ //counts through each character in "cloze elements"
      blankSpace += "◯"; //adds one circle for each character in "cloze" element
    }
    clozes[i].innerText = blankSpace; //replaces "cloze" content with circles
 }
</script>



RE: Anki Javascript help - トリピー♫ - 2016-01-18

I see the problem.

In the example I posted above, the javascript is looking for a <cloze>なんとか</cloze> element, not a <span class="cloze">なんとか</span> element.

You could almost fix this by changing one line in the JS on the card from 
var clozes = document.getElementsByTagName("cloze");
to
var clozes = document.getElementsByClassName("cloze");.

However, that causes a different problem. The code breaks because it never escapes dangerous characters like quotes. So when there is a section that says something like examples_jp.push("{{example 1_jp}}"); if the example 1_jp filed contains any double quotes, it will think the string ends at that point. You could write something to escape those characters, but in this case, it's easier just to avoid using any double quotes in your fields.

BTW, I found a mistake that I made. This part of the code:
Code:
   for (var k=0;k<examples_jp.length;k++){ //loops through J sentence array
      if (examples_jp[k] == ""){ //checks if field is empty
         examples_jp.splice(k,1); //removes empty fields from array
      }
   }
Should read this instead:
Code:
   for (var k=examples_jp.length-1;k>=0;k--){ //loops through J sentence array
      if (examples_jp[k] == ""){ //checks if field is empty
         examples_jp.splice(k,1); //removes empty fields from array
      }
   }



RE: Anki Javascript help - polyturn - 2016-01-18

Code:
<div id="ex_jp"></div>
<div id="ex_en"></div>
<script>
   var examples_jp = []; //creates empty array for J sentences
   var examples_en = []; //creates empty array for E sentences

   examples_jp.push("{{example 1_jp}}"); //adds J sentences to array
   examples_jp.push("{{example 2_jp}}");
   examples_jp.push("{{example 3_jp}}");
   examples_jp.push("{{example 4_jp}}");
   examples_jp.push("{{example 5_jp}}");
   examples_jp.push("{{example 6_jp}}");
   examples_jp.push("{{example 7_jp}}");
   examples_jp.push("{{example 8_jp}}");
   examples_jp.push("{{example 9_jp}}");
   examples_jp.push("{{example 10_jp}}");
   examples_jp.push("{{example 11_jp}}");
   examples_jp.push("{{example 12_jp}}");
   examples_jp.push("{{example 13_jp}}");
   examples_jp.push("{{example 14_jp}}");
   examples_jp.push("{{example 15_jp}}");
   
   examples_en.push("{{example 1_en}}"); //adds E sentences to array
   examples_en.push("{{example 2_en}}");
   examples_en.push("{{example 3_en}}");
   examples_en.push("{{example 4_en}}");
   examples_en.push("{{example 5_en}}");
   examples_en.push("{{example 6_en}}");
   examples_en.push("{{example 7_en}}");
   examples_en.push("{{example 8_en}}");
   examples_en.push("{{example 9_en}}");
   examples_en.push("{{example 10_en}}");
   examples_en.push("{{example 11_en}}");
   examples_en.push("{{example 12_en}}");
   examples_en.push("{{example 13_en}}");
   examples_en.push("{{example 14_en}}");
   examples_en.push("{{example 15_en}}");

   for (var k=examples_jp.length-1;k>=0;k--){ //loops through J sentence array
      if (examples_jp[k] == ""){ //checks if field is empty
         examples_jp.splice(k,1); //removes empty fields from array
      }
   }
random = Math.floor(examples_jp.length*Math.random()); //picks a random number

document.getElementById("ex_jp").innerHTML = examples_jp[random]; //puts J sentence on screen
document.getElementById("ex_en").innerHTML = examples_en[random]; //puts E sentence on screen

var clozes = document.getElementsByClassName("cloze"); //creates array of all "cloze" elements
for(var i=0;i<clozes.length;i++){ //loops through all "cloze" elements
   var blankSpace = ""; //creates empty string to replace "cloze" contents
   for (var j=0;j<clozes[i].innerText.length;j++){ //counts through each character in "cloze elements"
     blankSpace += "◯"; //adds one circle for each character in "cloze" element
   }
   clozes[i].innerText = blankSpace; //replaces "cloze" content with circles
}
</script>
Did I make a mistake? It still isn't working....


RE: Anki Javascript help - トリピー♫ - 2016-01-18

Yeah, I think you missed what I said about changing to getElementByClassName not working because of the problem with the quotes. You need to get the quotes out of the fields.

For example, look at the line below:
examples_jp.push("{{example 1_jp}}");
If the field example 1_jp contains カレー<span class="cloze">の方</span>が好き,
then the javascript thinks the field ends at the first quote ("カレー<span class=").
Then it doesn't know what to do with the rest of the characters in the field and the code breaks.

Another way to get around it is by swapping the double quotes in the javascript for single quotes:
examples_jp.push("{{example 1_jp}}"); --> examples_jp.push('{{example 1_jp}}');

Only do this with the examples_jp array though, not the examples_en array.
If you do this with the examples_en array, it will break for the same reason whenever you hit a contraction.


RE: Anki Javascript help - polyturn - 2016-01-19

Holy..... Wow, this is fascinating. Thank you very much.
Actually I tried changing the double quotes to single quotes but I had no idea that I had to leave the en arrays.
All that's left is to remove any double quotes in the english fields I guess.

One last question btw. Is there any way to retain the same randomized example when you flip the card? {{FrontSide}} doesn't seem to work.


RE: Anki Javascript help - トリピー♫ - 2016-01-19

It won't work correctly in either the template editor window (will show nothing on the back), nor if you use the preview feature in the card browser (will likely show a different random sentence.

It only works when actually studying the card. I always see the same sentence after I show the answer.
Keep in mind that I'm using Windows. I can't really speak for how it behaves on Mac or mobile.


RE: Anki Javascript help - トリピー♫ - 2016-01-21

Oh, I'm Sorry. You're right; {{FrontSide}} won't work since it will rerun the javascript from the front of the card.
Use this instead:
Code:
<div id="ex_jp"></div>
<div id="ex_en"></div>
<script>
 document.getElementById("ex_jp").innerHTML = sentences_jp[random];
 document.getElementById("ex_en").innerHTML = sentences_en[random];
</script>
<hr id=answer>

You can see it's basically the same as the front side, without the bit to generate a random example (since we've already done that) and without the cloze part hidden.


RE: Anki Javascript help - Vempele - 2016-01-21

(2016-01-21, 8:37 am)トリピー♫ Wrote: Oh, I'm Sorry. You're right; {{FrontSide}} won't work since it will rerun the javascript from the front of the card.
Hence the following in my first reply:

if (!document.getElementById("answer")) {
// Only run if there is no back of the card yet
}


RE: Anki Javascript help (randomly select a kanji from between 2-5 choices...) - トリピー♫ - 2016-01-22

Sage advice indeed.