Jwrede / Anki-KaTeX-Markdown

Creates a new Basic and a new Cloze Note Type that support Markdown and KaTeX
75 stars 5 forks source link

Tutorial of custom card type with KaTeX-Markdown support #31

Open pilgrimlyieu opened 2 years ago

pilgrimlyieu commented 2 years ago

Notice that many people are confused about how to make custom card type with KaTeX-Markdown support, I consider it important to make a tutorial to answer their confusion.

Basic

Take "Basic (type in the answer)" as an example. (Every card type can use the same method)

Open KaTeX and Markdown Basic and copy the code wrapped by <script> and </script> to your card type. (Pay attention to the side of the card!)

If your card type includes Cloze, open KaTeX and Markdown Cloze instead.

Front

1

Back

2

Basic Front (Up to now) ```html ```
Basic Back (Up to now) ```html ```
Cloze Front (Up to now) ```html ```
Cloze Back (Up to now) ```html ```

The result is like this

Front

3

Back

4

Then wrap field with html label. The format is <div id="XXX"><pre>{{Field}}</pre></div>

The Basic card default support id="front" in the front side and id="front", id="back" in the back side. The Cloze card default support id="front" in the front side and id="front", id="back" and id="extra" in the back side. If you have more field to be equipped with KaTeX-Markdown support, see Advanced

Front

5

Back

6

By the way, it's not advised to equip type field with KaTeX-Markdown. So I do not equip it. If you persist, the way is same.

If the text is in the center, you can modify Styling 7

Test markdown

# Test

Test **bold** and *italic*.

Test `code`.

```python
print("Hello World!")

Test math: $E=mc^2$

$$\mathrm{e}=\sum^{+\infty}_{i=0}\frac{1}{i!}$$


The final result is 

Front

![8](https://user-images.githubusercontent.com/80107081/160219360-43d4bf51-2fb7-4b96-8a30-5b93ebfa21ab.png)

Back

![9](https://user-images.githubusercontent.com/80107081/160219376-e1b5a5b8-68fc-4ae2-877b-a23f3592a839.png)

## Advanced

If you have more than two fields. You can add more `id` to satisfy your need.

I create a new template as an example. This template includes three fields: _Front_, _Extra1_ and _Extra2_

Firstly, search functions `render()` and `show()` in `<script></script>` like this

```js
function render() {
    renderMath("front");
    markdown("front");
    renderMath("back");
    markdown("back");
    show();
}

function show() {
    document.getElementById("front").style.visibility = "visible";
    document.getElementById("back").style.visibility = "visible";
}

Then add your id name. In my template is

  function render() {
      renderMath("front");
      markdown("front");
      renderMath("back");
      markdown("back");
+     renderMath("extra");
+     markdown("extra");
      show();
  }

  function show() {
      document.getElementById("front").style.visibility = "visible";
      document.getElementById("back").style.visibility = "visible";
+     document.getElementById("extra").style.visibility = "visible";
  }

Finally add HTML label

10

Notice

  1. Remember to add <pre></pre> label, or it'll cause lots of styling problems.

  2. If you use {{#Field}}{{/Field}} to wrap {{Field}}, Notice that if {{Field}} is empty, it'll interrupt the render of the later field.

Example:

{{#a}}
<div id="a"><pre>{{a}}</pre></div>
{{/a}}
<br>
{{#b}}
<div id="b"><pre>{{b}}</pre></div>
{{/b}}
<br>
{{#c}}
<div id="c"><pre>{{c}}</pre></div>
{{/c}}

<script>
...
  function render() {
      renderMath("a");
      markdown("a");
      renderMath("b");
      markdown("b");
      renderMath("c");
      markdown("c");
      show();
  }

  function show() {
      document.getElementById("a").style.visibility = "visible";
      document.getElementById("b").style.visibility = "visible";     
      document.getElementById("c").style.visibility = "visible";
  }
...
</script>

If {{b}} is empty, {{a}} will render normally while {{c}} could not.

If you delete {{#b}}{{/b}} it works normal again.

Solution:

Add try catch wrap to the render function (maybe also show function) like

function render() {
    try {renderField("front")}  catch {}
    try {renderField("back")}   catch {}
    try {renderField("extra")}  catch {}
    try {renderField("extra1")} catch {}
    try {renderField("extra2")} catch {}
    show();
}

function renderField(field) {
    renderMath(field);
    markdown(field);
}

function show() {
    try {document.getElementById("front").style.visibility  = "visible"} catch {}
    try {document.getElementById("back").style.visibility   = "visible"} catch {}
    try {document.getElementById("extra").style.visibility  = "visible"} catch {}
    try {document.getElementById("extra1").style.visibility = "visible"} catch {}
    try {document.getElementById("extra2").style.visibility = "visible"} catch {}
}

Q&A

  1. How to add KaTeX macros?

See Where to store persistent KaTex macros

  1. If I prefer other delimiters to $ and $$, what should I do?

See Dollar sign in code block issues or Extraneous non-working HTML tags in a code block

  1. The new card template doesn't support preview in the editor.

See Extraneous non-working HTML tags in a code block

  1. Why doesn't \pu{...} syntax work normally?

Related to https://github.com/Jwrede/Anki-KaTeX-Markdown/issues/17#issuecomment-922436281

Problem: There is no space between number and unit.

Solution: Remove the starred code

function replaceHTMLElementsInString(str) {
*   str = str.replace(/&nbsp;/gi, " ");
    str = str.replace(/&tab;/gi, "  ");
    str = str.replace(/&gt;/gi, ">");
    str = str.replace(/&lt;/gi, "<");
    return str.replace(/&amp;/gi, "&");
}

and add it to this function like the starred line

function replaceInString(str) {
    str = str.replace(/<[\/]?pre[^>]*>/gi, "");
    str = str.replace(/<br\s*[\/]?[^>]*>/gi, "\n");
    str = str.replace(/<div[^>]*>/gi, "\n");
    str = str.replace(/<[\/]?span[^>]*>/gi, "")
    str = str.replace(/<\/div[^>]*>/gi, "\n");
*   str = str.replace(/&nbsp;/gi, " ");
    return replaceHTMLElementsInString(str);
}
  1. There are leftover </div> elements in cards.

Related to https://github.com/Jwrede/Anki-KaTeX-Markdown/issues/31#issuecomment-1264120987, Thank @keithadams!

Solution:

Here is the problem code:

CleanShot 2022-09-30 at 16 07 38@2x

I've added str = to the beginning and made the regex case insensitive with gi like the other lines.

str = str.replace(/<\/div[^>]*>/gi, "\n");

If you have more questions, be free to ask. I'll reply you as soon as possible.


My Anki scripts & stylings is hosted in this repo. Anyone is welcome to have a look!

Jwrede commented 2 years ago

Wow thanks so much for your effort, I'll link this post to the people that asked for basic (type in the answer). Really happy that you're helping the community, sorry that I kind of abandoned this project because of my limited time

keithadams commented 2 years ago

Thanks for the tutorial, @pilgrimlyieu. I followed the steps and everything is working except the syntax highlighting. The <code> block has the correct class of language-python but no syntax highlighting.

pilgrimlyieu commented 2 years ago

Thanks for the tutorial, @pilgrimlyieu. I followed the steps and everything is working except the syntax highlighting. The <code> block has the correct class of language-python but no syntax highlighting.

Sorry for my late reply. Because of the limited time, I can not maintain this tutorial well even I've learnt more and am about to share.

Can you give me an example or a screenshot? I've tested it and it works normally in my circumstance.

Snipaste_2022-07-29_21-37-09

```python
import sys

print('hello world')

def test(arg1, arg2):
    if arg1 != arg2:
        return arg1 - arg2

print(test(2, 3))
keithadams commented 2 years ago

Thanks for your reply. Your code example looks great. Here is my Anki version info and some screenshots.

    Anki 2.1.54 (b6a7760c) Python 3.9.7 Qt 6.3.1 PyQt 6.3.1
    Platform: Mac 12.4
    Flags: frz=True ao=True sv=2

Markdown Example:

Code Example:

Console Log:

pilgrimlyieu commented 2 years ago

@keithadams Can you show me the source code? If _highlight.js can not render python code, its warning should be

Could not find the language 'python', did you forget to load/include a language module?

Is this your Code Example source code?

```python
import sys

print('hello world')

def test(arg1, arg2):
    if arg1 != arg2:
        return arg1 - arg2

print(test(2, 3))


If not, can you show me your source code? Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>X</kbd> to copy.
keithadams commented 2 years ago

Is this your Code Example source code?

@pilgrimlyieu Yes. I used that exact code for the Front field.

pilgrimlyieu commented 2 years ago

@pilgrimlyieu Yes. I used that exact code for the Front field.

Confusing. Can you show me the code of your card(including front and back side HTML and styling CSS)? I'll have a check.

keithadams commented 2 years ago

Github Gist of my Front Template, Back Template, and Styling.

pilgrimlyieu commented 2 years ago

Github Gist of my Front Template, Back Template, and Styling.

Snipaste_2022-07-30_17-56-17

Works normally in my case too. Can you try to disable other addons to check if it is the issue of addons?

keithadams commented 2 years ago

Yes, I disabled all addons and restarted Anki but have the same result 🤷

pilgrimlyieu commented 2 years ago

Yes, I disabled all addons and restarted Anki but have the same result 🤷

I have no idea temporarily. Maybe you can unzip and copy contents of this Anki-Markdown-KaTeX.zip package to ~/collection.media to have a try.

Anki-Markdown-KaTeX.zip

keithadams commented 2 years ago

That worked! There must be something wrong with the files my system is pulling down. I'll take a look at the files later today and see if I can determine the culprit. I'll post my results. Thanks for your help!

JS Example Highlighted in Anki

pilgrimlyieu commented 2 years ago

That worked! There must be something wrong with the files my system is pulling down. I'll take a look at the files later today and see if I can determine the culprit. I'll post my results. Thanks for your help!

JS Example Highlighted in Anki

Glad to hear that!

keithadams commented 2 years ago

I think some cached versions of the files in my "collection.media" folder were causing the issue. Maybe when I tried the plugin a while back and scripts in the card templates kept relying on these older versions.

I cleared the "collection.media" folder and tried to recreate the problem but I can't. @pilgrimlyieu's tutorial works for me now and so do the files generated after installing the plugin.

pilgrimlyieu commented 2 years ago

I think some cached versions of the files in my "collection.media" folder were causing the issue. Maybe when I tried the plugin a while back and scripts in the card templates kept relying on these older versions.

I cleared the "collection.media" folder and tried to recreate the problem but I can't. @pilgrimlyieu's tutorial works for me now and so do the files generated after installing the plugin.

I've tried to delete highlight.js and highlight.css and download a version that includes no language highlight from highlight.js, but I still can not get the same console log. Anyway, this issue is solved, maybe.

amoksito commented 2 years ago

How can I change the theme for my code blocks?

pilgrimlyieu commented 2 years ago

How can I change the theme for my code blocks?

Sorry for my late reply. You can download a package in highlight.js, unzip it and choose a style in styles. For example I'm using atom-one-dark-reasonable.min.css. Put the style file to collection.media directory. Then change code in both side.(The following code is my settings, maybe different from yours, but is similar)

var getResources = [
    getCSS("_katex.css", "https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css"),
    getCSS("_highlight.css", "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/atom-one-dark-reasonable.min.css"),
    getScript("_highlight.js", "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"),
    getScript("_katex.min.js", "https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.js"),
    getScript("_auto-render.js", "https://cdn.jsdelivr.net/gh/Jwrede/Anki-KaTeX-Markdown/auto-render-cdn.js"),
    getScript("_markdown-it.min.js", "https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js"),
    getScript("_markdown-it-mark.js", "https://github.com/markdown-it/markdown-it-mark/blob/master/dist/markdown-it-mark.js")
];

Change _highlight.css to your style file name or rename your style file name to _highlight.css.

Here is the output.

Snipaste_2022-07-29_21-37-09

amoksito commented 2 years ago

Thank you very much!

keithadams commented 2 years ago

@pilgrimlyieu I think there is a bug in the tutorial. I was getting leftover </div> elements in my cards.

Here is the problem code:

CleanShot 2022-09-30 at 16 07 38@2x

I've added str = to the beginning and made the regex case insensitive with gi like the other lines.

str = str.replace(/<\/div[^>]*>/gi, "\n");
pilgrimlyieu commented 2 years ago

@pilgrimlyieu I think there is a bug in the tutorial. I was getting leftover </div> elements in my cards.

You are right, thanks! Due to my limited knowledge of JavaScript, I didn't check the code. I will add it to the tutorial.