AnkiのJavaScriptライブラリの読み込み

# はじめに
これは、[JavaScript Advent Calendar 2022](https://qiita.com/advent-calendar/2022/javascript)の21日目の記事となります。

大学入学共通テストまで2ヶ月ほどになりました。たくさんの情報を効率よく覚えたい、タイパよく暗記したくありませんか？
今回紹介するのは暗記アプリ「Anki」のJavaScriptを使用したカスタマイズとなります。

以前、JavaScriptを使用したカスタマイズとして英作文の組み立てを作成しました。
これをもっとリッチな表現にしたいと思っています。

https://qiita.com/yaju/items/38eba28535c886fcc708

# Ankiとは
Ankiとは、Damien Elmes氏がプログラミング言語Pythonを用いて開発した、暗記を目的としたオープンソフトウェアです。その名の通り、日本語の「暗記」から名付けられており、フラッシュカードを自由にカスタマイズできる機能が豊富なことで知られています。

「忘却曲線」という単語を聞いたことはありませんでしょうか？、時間が経過するにつれて記憶は薄れていくという理論です。記憶は1日経過しただけで半分以上忘れてしまいます。
しかし、適切なタイミングで復習すれば記憶の忘却のスピードは緩やかになり、結果としてすぐに忘れてしまう短期記憶から、時間が経っても忘れない、長期記憶に移行するのです。

Ankiは、適切なタイミングで復習出来るように出題をコントロールしてくれるアプリです。

https://eigonote.jp/2020/09/%E3%80%90%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E3%80%91%E6%9A%97%E8%A8%98%E3%82%A2%E3%83%97%E3%83%AAanki%E3%81%A7%E5%8D%98%E8%AA%9E%E5%AD%A6%E7%BF%92%E3%82%92%E8%B6%85%E7%B5%B6%E5%8A%B9/

「覚えていたい期間の10～30%程度の間隔で復習を繰り返すことが、最も高い保持率に結びつく」という説があります

https://gendai.media/articles/-/70237?imp=0

## Markdown and KaTeX Support
Markdownと数式に対応する Add-on は公開されています。

https://ankiweb.net/shared/info/1087328706

# JavaScriptによる機能拡張
AnkiはPythonを利用したアドオンを作成することが出来るのですが、PC向け(Windows、Mac、Linux)のみで、モバイル向けは対象外です。

JavaScriptによる機能拡張は、PCやモバイルで使用可能です。
AnkiのPC版はQWebEngineを使用しています。ES6 modulesに対応しています。

## CDNの利用
オンライン環境(インターネット接続が可能)であれば、JavaScriptライブラリーをCDNから取得し利用すると便利です。

## collection.mediaフォルダの利用
オフライン環境の場合、JavaScriptライブラリーをcollection.mediaフォルダに保存しておくとでもオフライン状態でも動作するようになります。

collection.mediaフォルダは、すべてのクライアント (Anki Desktop、AnkiMobile など) 間で同期される仕組みとなっています。
この時だけインターネット接続する必要があります。

### 使用方法
Ankiのネームルールとしてファイル名の先頭にアンダースコアを追加して、collection.mediaフォルダに保存します。

```text:例
await injectScript('https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js');
↓
await injectScript('_marked.js');
```

https://forums.ankiweb.net/t/how-to-include-external-files-in-your-template-js-css-etc-guide/11719


## 動的ロード
カード テンプレートのインライン Javascript は Anki 2.1 で[非同期に評価](https://web.archive.org/web/20200202135059/https://apps.ankiweb.net/docs/addons.html#webview-changes)されるため、外部ライブラリを使用する関数は意図したとおりに動作しない場合があります。
これに対するいくつかの回避策は、インライン スクリプトを使用せず、js ファイルを動的にロードすることです。
ES6 Promise APIを使用して動的スクリプト ローダーを介して外部ライブラリをロードする方法になります。

例として Markdownで書かれた内容をHTMLに変換するライブラリー「marked.js」とコードをシンタックスハイライトする(highlight.js)を利用して
FibonacciのPythonコードを表示させてみます。

![スクリーンショット 2024-10-23 23.57.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/d745333a-6a8b-da73-084c-53671fb2b2f9.png)
![スクリーンショット 2024-10-24 0.00.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/c6611696-1644-a0f6-ea6a-1ab8acdfb184.png)

```js
{{FrontSide}}

<script>
var injectScript = (src) => {
    return new Promise((resolve, reject) => {
        const script = document.createElement('script');
        script.src = src;
        script.async = true;
        script.onload = resolve;
        script.onerror = reject;
        document.head.appendChild(script);
    });
};

var injectCSS = (src) => {
    return new Promise((resolve, reject) => {
        const link = document.createElement('link');
        link.rel = "stylesheet";
        link.href = src
        link.async = true;
        link.onload = resolve;
        link.onerror = reject;
        document.head.appendChild(link);
    });
};

(async () => {
    if (!('marked' in globalThis)) {
        await injectCSS('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/styles/default.min.css');
        await injectScript('https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js');
        await injectScript('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.6.0/build/highlight.min.js');
    }

    document.querySelectorAll('.md').forEach((el) => {
        var highlight = function(code, lang, callback){
            return hljs.highlight('py',code).value;
        }

        var renderer = new marked.Renderer;
        var html = marked(el.innerText, {
            highlight: highlight,
            renderer: renderer,
        });
        el.innerHTML = html;
    });
})();
</script>

<hr id=answer>

<pre class="md" style="text-align: left;">
{{裏面}}
</pre>
```

https://www.reddit.com/r/Anki/comments/e005jx/load_js_functions_in_external_file/

https://forums.ankiweb.net/t/linking-to-external-javascript/1713



## 質問と回答の共有
window オブジェクトが Anki カードの質問と回答の呼び出し間で共有されると述べています。
質問で乱数を生成し、同じ値が回答で使用できることを意味します。

https://stackoverflow.com/questions/54423183/javascript-works-in-2-0-version-of-anki-but-not-in-2-1-version

【2023/01/03追記】

https://qiita.com/yaju/items/1b3b6ce9f8a914f48de8

# 最後に
今回、英語の整序問題(並び替え)をリッチな表現にしたいと思って色々調べました。
何かのお役に立てれば幸いです。