An image to describe post

Yankiプラグインを使用した穴埋めノートの作成方法に加え、共有デッキ「可输入答案的填空模板」を利用して、見た目が良く便利な穴埋めノートを作成する方法を紹介します。最後に、Templater Hotkeyスクリプトを使ってホットキーで素早く穴埋めフィールドを作成する方法を説明します。

◎ 例
中華民國憲法 第1條
中華民國基於三民主義,為民有民治民享之民主共和國。
中華民國基於{{三民主義}},為{{c1::民有}} {{c2::民治}} {{c3::民享}} 之民主共和國。

1. Yanki Cloze

  • 2つのチルダで穴埋めデータを囲みます。
  • チルダを順番に {{c番号::データ}} 形式にエクスポートします。番号は1から増加します。
中華民國憲法 第1條
中華民國基於~~三民主義~~,為~~民有~~ ~~民治~~ ~~民享~~ 之民主共和國。
  • 同期後のAnkiの表面:
中華民國憲法 第1條
中華民國基於{{c1::三民主義}},為{{c2::民有}} {{c3::民治}} {{c4::民享}} 之民主共和國。
  • 穴埋めの数だけカードが生成されます。

1.1. ノートタイプのスタイル変更

  • メニュー 【ツール】→【ノートタイプを管理】、 【Yanki - Cloze】を選択→【カード】
  • 【テンプレート】→【スタイル】
    • .card: text-align: left を使用して内容を左寄せにします。
    • .cloze: 穴埋めデータを太字の青色に変更します。
.card {
    font-family: arial;
    font-size: 20px;
    text-align: left;
    color: black;
    background-color: white;
}

.cloze {
 font-weight: bold;
 color: blue;
}

1.2. 同じグループのCloze

  • 現在、Yankiでは同じグループの穴埋めを設定できません。つまり、{{c2::から{{c4::までをすべて{{c1::として同じグループに設定することです:
中華民國基於~~三民主義~~,為{{c1::民有}} {{c1::民治}} {{c1::民享}}之民主共和國。

gh|500

2. 共有デッキ:答えを入力できる穴埋めテンプレート

  • 共有デッキをブラウズ:可输入答案的填空模板 - 翏央 / chehil - AnkiWeb
  • ダウンロードした .apkg ファイルをローカルに保存します。
  • Anki 【デッキ】→【ファイルをインポート】、ダウンロードした .apkg ファイルを選択→【インポート】、完了後、インポートウィンドウを閉じます。
    gh|500
  • インポートされたデッキ名:*可输入答案的填空模板、インポートされたノートカードをブラウズします。
  • QUESTIONフィールドの内容:
床前明月光,{{疑是地上霜}}。
举头望明月,{{低头思故乡}}。
  • カード表面をブラウズする際、ノートタイプ内のJavaScriptスクリプトが、2つの中括弧内のテキストを特別に処理します。

    gh|500

  • 穴埋め箇所に答えを入力し、裏面で正誤を確認できます。裏面:

    gh|500

2.1. ノートタイプ:Type Cloze @翏央chehil

  • 表面テンプレート
<div class=slide>
  <div class=qu>—— Question ——</div>
  <p></p>
  <div class=question>{{QUESTION}}</div>
</div>

<script>
  TYPE = '1';
  function toggle(cloze) {
    var key = cloze.getElementsByClassName("key")[0];
    var entry = cloze.getElementsByClassName("entry")[0];
    if (entry.style.display == "none") {
      if (TYPE) {
        key.style.display = "none";
        entry.style.display = "inline";
        if (entry.contentEditable == "true") {
          entry.focus();
          entry.onblur = function() {
            answer = entry.textContent.trim()
            if (answer == key.textContent.trim()) {
              entry.style.color = "green";
              entry.innerHTML = answer + '✔';
            } else {
              entry.style.color = "red";
              entry.innerHTML = answer + '✘';
            }
            key.style.opacity = 1;
            entry.contentEditable = false;
          }
        }
      } else {
        key.style.opacity = 1 - key.style.opacity;
      }
    } else {
      entry.style.display = "none";
      key.style.display = "inline";
    }
  }

  [].forEach.call(document.querySelectorAll('.question'),
    function(V0) {
      V0.innerHTML = V0.innerHTML.replace(/\{\{((?:.|\r?\n)+?)\}\}/g,
        '<span class="cloze" onclick="toggle(this)">' +
        '  <span class="key" style="opacity:0">$1</span>' +
        '  <span class="entry" style="display:none;" contenteditable="true"></span>' +
        '</span>')
    });
</script>
  • 裏面テンプレート
    • &emsp;: 全角スペース
<div class=qu>—— Question ——</div>
<p></p>
<div class=question>{{QUESTION}}</div>
<hr color=#ebedec>
<div class=slide>
  <div class=an>—— Answers ——</div>
  <div class=hr3></div>
  <div class=hr4></div>
  <p></p>
  <div class=answer>{{ANSWER}}</div>
  <p></p>
{{#TIPS}}
  <div class=Tips><ti>TIPS</ti>&emsp;{{TIPS}}</div>
{{/TIPS}}
</div>

<script>
  TYPE = '1';
  function toggle(cloze) {
    var key = cloze.getElementsByClassName("key")[0];
    var entry = cloze.getElementsByClassName("entry")[0];
    if (entry.style.display == "none") {
      if (TYPE) {
        key.style.display = "none";
        entry.style.display = "inline";
        if (entry.contentEditable == "true") {
          entry.focus();
          entry.onblur = function() {
            answer = entry.textContent.trim()
            if (answer == key.textContent.trim()) {
              entry.style.color = "green";
              entry.innerHTML = answer + '✔';
            } else {
              entry.style.color = "red";
              entry.innerHTML = answer + '✘';
            }
            key.style.opacity = 1;
            entry.contentEditable = false;
          }
        }
      } else {
        key.style.opacity = 1 - key.style.opacity;
      }
    } else {
      entry.style.display = "none";
      key.style.display = "inline";
    }
  }

  [].forEach.call(document.querySelectorAll('.question'),
    function(V0) {
      V0.innerHTML = V0.innerHTML.replace(/\{\{(.+?)\}\}/g,
        '<span class="cloze" onclick="toggle(this)">' +
        '  <span class="key" style="opacity:0">$1</span>' +
        '  <span class="entry" style="display:none;" contenteditable="true"></span>' +
        '</span>')
    });
  [].forEach.call(document.querySelectorAll('.key'),
    function(key) {
      key.style.opacity = 1
      key.style.display = "inline";
    });
  [].forEach.call(document.querySelectorAll('.entry'),
    function(entry) {
      entry.style.display = "none";
    });
</script>
  • スタイル
@font-face { font-family: STsong; src: url('_STsong.TTF'); }
@font-face { font-family: STfangsong; src: url('_STfangsong.TTF'); }
@font-face { font-family: kt; src: url('_kt.ttf'); }

.card {
 	padding: 15px 20px;
	font-family:STsong, Arial, serif;
	font-size: 25px;
 	color: #000;
 	background: #ebedec;
}

.qu {
 	font: 30px Times;
 	font-style: oblique;
 	text-align: center;
}

.an {
 	font: 30px Times;
 	font-style: oblique;
 	text-align: center;
}

.question {
	color: #4c5870;
	font-weight: bolder;
	letter-spacing: 0.016em;
	line-height: 150%;
	text-align: justify
}

.answer {
	color: #4c5870;
	font-weight: bolder;
	letter-spacing: 0.016em;
	line-height: 150%;
	text-align: justify
}

ti{
	border-radius: 9px;
	padding: 4px 3px 2px 8px;
 	font: bold 15px Arial;
	text-align: left;
	letter-spacing: 1px;
	color: #ebedec;
	background: #FD7013;
}

.Tips{
 	min-height: 24px;
 	border-top: 1px solid #FD7013;
 	padding: 17px;
	font-size: 20px;
	font-family:仿宋;
	font-weight: bold;
 	text-align: left;
	color: #222831;
	background:#FFFFF2;
	box-shadow: 2px 2px 5px #aaaaaa;
}

.slide {
	position:relative;
	-webkit-animation:slide 2s 0s;
	-webkit-animation-fill-mode:forwards; }

@-webkit-keyframes slide {
	0%		{ opacity: 0;     top: 40px; }
	100%		{ opacity: 1;     top: 0px; }
}

.card.nightMode {
	color: #ebedec;
	background: #121212;
}

.nightMode .question {
	color: #9ba6b2;
}

.nightMode .answer {
	color: #9ba6b2;
}

.nightMode ti {
	color: #121212;
	background: #f9a825;
}

.nightMode .Tips {
	border-top: 1px solid #f9a825;
	color: #ebedec;
	background:#1e1e1e;
	box-shadow: 2px 2px 5px #000000;
}

.cloze {
	color: #008792;
	padding:0 2px;
	border-bottom: solid;
	font-family:kt;
	font-weight:bold;
	letter-spacing:0.002em
}

.nightMode .cloze {
	color: #65bd7b
}

2.2. Yanki - Basicで翏央の穴埋めテンプレートを使用する

  • テンプレート内の{{QUESTION}}{{Front}}に変更します。
  • テンプレート内の{{ANSWER}}{{Back}}に変更します。
  • {{TIPS}}関連の内容を削除します。
  • スタイルを挿入します。

3. Anki組み込みのフィールド構文

  • {{#フィールドA}}: 「フィールドA」という名前のフィールド内容が空の場合、 {{#フィールドA}}から {{/フィールドA}} までのデータは表示されません。
    • 上記の裏面テンプレートでは、TIPSフィールドに内容がない場合、{{#TIPS}}から{{/TIPS}}までの内容は表示されません。
  • {{^フィールドA}}: 「フィールドA」という名前のフィールド内容が空の場合、{{^フィールドA}}から{{/フィールドA}} までの内容が表示されます。
  • {{type:フィールド名}}: 表面と裏面の両方に配置しないと機能しません。入力ボックス機能。入力ボックスのスタイル:
input#typeans {
  text-align: center;
  margin: 6px 0;
  margin-left: -14px;
  font-size: 22px;
  padding: 6px 12px;
  outline-style: none;
  color: #18577F;
}
  • 穴埋め{{cloze:フィールド名}}入力:{{type:cloze:フィールド名}}

4. 穴埋め記号の高速挿入:Templater Hotkeyを使用

  • 穴埋めにしたいテキストを選択した後、キーを押して必要な記号を素早く挿入します。
キー 機能 ファイル名 prefix
Alt+` 翏央の穴埋め用二重中括弧 {{テキスト}} を挿入 Cmd-anki-cloze.md {{
Alt+1 Ankiの1番目の穴埋めフィールド {{c1::テキスト}} を挿入 Cmd-anki-cloze-c1.md {{c1::
Alt+2 Ankiの2番目の穴埋めフィールド {{c2::テキスト}} を挿入 Cmd-anki-cloze-c2.md {{c2::
以下同様...

4.1. 手順

  1. 必要な.mdファイルを作成し、Templaterスクリプトの内容を貼り付けます。
  2. Templaterのオプション設定で、各.mdファイルを追加します。
  3. ホットキー設定で対応するキーを設定します。

▼ Cmd-anki-cloze-c1.md (prefix変数を対応するテキストに変更します)

<%*
let selObj = window.getSelection();
let text = selObj.toString();
let prefix = "{{c1::";  // プレフィックスを変更
let isClozed = false;
if (text.startsWith(prefix)) {
  isClozed = true;
  text = text.substring(prefix.length)
}
if (text.endsWith("}}")) {
  isClozed = true;
  text = text.substring(0, text.length-2)
}
if (!isClozed) {
  text = prefix + text + "}}";
}
return text;
%>

5. 💡 関連リンク

💡 解説記事: https://jdev.tw/blog/8477/
✅Yanki: https://github.com/kitschpatrol/yanki-obsidian
✅ 可输入答案的填空模板 - 翏央: https://ankiweb.net/shared/info/356679663

6. 解説動画

##