Skip to content

Instantly share code, notes, and snippets.

@fasiha
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fasiha/546ff61f60541c84d9c8 to your computer and use it in GitHub Desktop.
Save fasiha/546ff61f60541c84d9c8 to your computer and use it in GitHub Desktop.
Response to Ben Bullock of Sljfaq regarding a request to make a public API to the Sljfaq kanji recognizer

Demo: Anki and iframes for practicing kanji handwriting.

Summary

Here's an (edited) message I wrote to Ben Bullock of sljfaq demonstrating how one could embed an iframe in Anki cards, load a remote website in that iframe, and get selections therein back to Anki, with a request that such a feature be added to the kanji recognizer.

If you're interested in this, please post a message endorsing the idea to the sljfaq Google group.

Background

Anki is a popular flashcard app in which flashcards are basically HTML/CSS/Javascript pages, so in order to practice kanji handwriting, one could imagine embedding sljfaq's kanji recognizer in the front of the card as an iframe in which one writes the kanji and then selects the right one, which then magically appears in the parent page as the answer. Believe it or not, everyone has been using Anki for kanji studies solely by self-grading.

Details

Here's an example of how this could work. I made a sample webpage that I'm serving locally at http://localhost:8888/target.html and its contents are at https://gist.github.com/fasiha/c07cdbfbf636873497ec#file-target-html and reproduced here:

<html>
<head>
  <meta charset="UTF-8">
  <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<script>
window.addEventListener("message", receiveMessage, false);
 
function receiveMessage(event) {
    var resp = '' + window.getSelection();
    d3.select('body').append('div').text("Got message from "  + event.origin + ". Sending: " + resp);
    event.source.postMessage(resp, '*');
}
</script>
 
<h1>Some kanji follows</h1>
<div>一二三四五六七八九十口日月田目古吾冒朋明唱晶品呂昌早旭世胃旦胆亘凹凸旧自白百中千舌升昇丸寸肘専博占上下卓朝嘲只貝唄貞員貼見児元頁頑凡負万句肌旬勺的首乙乱直具真工左右有賄貢項刀刃切召昭則副別丁町可頂子孔了女好如母貫兄呪克小少大多夕汐外名石肖硝砕砂妬削光太器臭嗅妙省厚奇川州順水
</div>
</body></html>

It's just a list of kanji with an event handler using the Web Messaging API, which will reply to a message with its selection, across host origins. This will be the child iframe.

The parent page is HTML stored in Anki: https://gist.github.com/fasiha/c07cdbfbf636873497ec#file-front-html and reproduced below:

{{cloze:Text}}
<br>
{{type:cloze:Text}}
 
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
 
<button id="grab-button" onclick="sendMessageToGetSelection();">Grab selection from iframe</button>
 
<iframe id="my-iframe"  width="800" height="90" src="http://localhost:8888/target.html"></iframe>
 
<script>
window.addEventListener("message", receiveMessage, false);
 
function receiveMessage(event) {
    d3.select('body').append('div').text(function() {return "received event!: " + event.data;});
    document.getElementById('typeans').value = event.data;
}
 
function sendMessageToGetSelection() {
    var iframe= document.getElementById('my-iframe');
    var iwin= iframe.contentWindow || iframe.contentDocument.defaultView;
 
    iwin.postMessage('gimme selection plz', '*');
}
</script>

It basically consists of a bit of Anki syntax, a button that'll send a message to the child frame, a function that'll receive the response (containing the selected text), and some code to inject that response into Anki's answer field, and append it to the DOM for verification.

Here's what that looks like in Anki:

Here's what that looks like in Anki

If I select a bunch of text in the child iframe, and click the button, it looks like this:

With a bunch of text

Of course I got over-excited at seeing this work. I select the right answer and click the button:

The right answer

Here's what it looks like when I submit this as the answer:

Submitted answer

Looks like I got it right! (The back of the card is instructed to contain a copy of the front of the card, so that's why you see all the things I selected-via-click on the back here).

Now imagine if this could work with sljfaq's kanji recognizer. Here's what it looks like in the iframe:

sljfaq in iframe

(The Mac I was using was repossessed by a family member so I took this screenshot in Windows.) Of course the button doesn't do anything because the page isn't listening for messages.

Mozilla gives a good overview of how to make this secure by checking the origin of message events. I circumvented this by using '*' as the target in my calls to postMessage(). I think this is ok for this application (a single page at kanji.sljfaq.org/draw.html or hopefully a simplified page like you showed in your first response earlier in the year), but maybe not, we can hash out the technical details. Ideally, one wouldn't have to click anything in Anki's parent page, and just clicking on a kanji in whatever iframe you eventually make available will automatically send the message to window.parent.

I've posted the above screenshots as a slideshow at http://imgur.com/a/o7BLF and at the bottom I've asked for Anki users who are interested in seeing this a reality to post here---I hope we don't hear crickets, that'd be embarrassing, but hopefully, even if nobody else chimes in, the above can convince you that this is worthwhile at least for me, because here's what my current Anki kanji practice winds up looking like:

Current kanji practice with Anki involves paper and pencil

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment