How to edit the collection on the latest anki dev?

I was trying to use the plugin Advanced Copy Fields - AnkiWeb Advanced Copy Fields to edit my collection, but it was not changing my notes after I updated to the latest commit on the main branch.

Then, I wrote my own script to edit my notes like the following, but neither my script was changing my notes on my collection. Do I need to flush something else now?


for name, did in mw.col.db.execute(f"select name, id from decks"):
    print(f"Deck name {name}, did {did}.")

# AllMyDecksRootLanguagesJapaneseKana (Katakana/Hiragana)
source_deck_did = 1582942327697

target_field = "BottomButtons"

target_note_type_name = "Katakana to Hiragana"

value_to_add = \
"""
<script>
function tryinput(event)  {
    if( $('#try').val() )
    {
        if( $('#try').val() != $('#get').val() ) {
            $('#try').css({'background-color': 'red'});
        }
        else {
            $('#try').css({'background-color': '#0f0'});
        }
    }
    else {
        $('#try').css({'background-color': 'white'});
    }
}
$('#try').on('compositionstart', tryinput);
$('#try').on('compositionend', tryinput);
$('#try').on('compositionupdate', tryinput);
$('#try').on('change', tryinput);
$('#try').on('keyup', tryinput);
$('#try').on('keydown', tryinput);
</script>
"""

for nid, in mw.col.db.execute(f"select id from notes"):
    note = mw.col.getNote(nid)
    note_type = note.note_type()

    if note_type["name"] == target_note_type_name:
        print(f"Changing note type {note.id}...")
        cards = note.cards()
        first_card = cards[0]
        deck_id = first_card.did

        if deck_id == source_deck_did:
            print(f"Changing deck {note.id}...")
            note[target_field] = value_to_add
            note.flush()

.flush() should still work. I suggest you start by boiling it down to the minimum script necessary to reproduce the problem.

I simplified the example to this and I run it twice in a row:

>>> target_field = "BottomButtons"
... 
... for nid, in mw.col.db.execute(f"select id from notes where id = 1296499533072"):
...     note = mw.col.getNote(nid)
...     print(f"Changing on deck from '{note[target_field]}'...")
...     note[target_field] = 'Changed'
...     note.flush()
...     print(f"Changing deck {note.id} to '{note[target_field]}'...")
...     break
Changing on deck from 's'...
Changing deck 1296499533072 to 'Changed'...

>>> target_field = "BottomButtons"
... 
... for nid, in mw.col.db.execute(f"select id from notes where id = 1296499533072"):
...     note = mw.col.getNote(nid)
...     print(f"Changing on deck from '{note[target_field]}'...")
...     note[target_field] = 'Changed'
...     note.flush()
...     print(f"Changing deck {note.id} to '{note[target_field]}'...")
...     break
Changing on deck from 'Changed'...
Changing deck 1296499533072 to 'Changed'...

Then, when focused on the browser window to see if the note actually changed, but the original text stayed the same.

Then, I went back to the debug window and I run the command again, and this was the output:

>>> target_field = "BottomButtons"
... 
... for nid, in mw.col.db.execute(f"select id from notes where id = 1296499533072"):
...     note = mw.col.getNote(nid)
...     print(f"Changing on deck from '{note[target_field]}'...")
...     note[target_field] = 'Changed'
...     note.flush()
...     print(f"Changing deck {note.id} to '{note[target_field]}'...")
...     break
Changing on deck from 's'...
Changing deck 1296499533072 to 'Changed'...

As you can see, the note was reverted to the original value. I tried running the command again, after closing the browser window, then, when I opened the browser window to check the contents, and now the note was for the first time actually changed.

Also, anki is eating my script tags, i.e., if I run this note replace:

>>> target_field = "BottomButtons"
... 
... for nid, in mw.col.db.execute(f"select id from notes where id = 1296499533072"):
...     note = mw.col.getNote(nid)
...     print(f"Changing on deck from '{note[target_field]}'...")
...     note[target_field] = r'''
... before script
... <script>
... inside script
... </script>
... after script
... '''
...     note.flush()
...     print(f"Changing deck {note.id} to '{note[target_field]}'...")
...     break
Changing on deck from 'before script

after script
'...
Changing deck 1296499533072 to '
before script
<script>
inside script
</script>
after script
'...

Anki is skipping the contents of <script>...</script> and only adding this to my note:
image

This behavior is quite annoying because I share common javascript code using a field with it. I do this because my notes have about 20 cards and copying big blocks of code in all of them is difficult, while just setting a field with the code is easier to update all of them at once.

Also, I think Anki has eaten all my collection fields with <script>...</script> contents when updated yesterday to the main branch. I think this is because my cards were working fine, but after updating, all my script tags went missing. That is why I was trying to add them back today.

Before updating to the last 200 commits on the main branch, I could add fields with <script>...</script> contents without any problems. Inclusive, I used the Advanced Copy Fields - AnkiWeb addon to add my <script>...</script> contents last time, but this time the addon could not change my notes or add the <script>...</script> contents.

Scripts are expected to be in your card template if anywhere, not inside individual fields. If you’re including note-specific data, that can be represented as text and then parsed by a script in the template.

I reverted back 200 commits on the main branch and opened an anki backup, and I can confirm my script code is there:

It means the latest version of Anki (about 200 commits ago) is deleting my script code in my fields.

I do not have specific data, I have common code I run for each template, as well buttons, not only javascript code:

... some HTML buttons

<script>
function tryinput(event)  {
    if( $('#try').val() )
    {
        if( $('#try').val() != $('#get').val() ) {
            $('#try').css({'background-color': 'red'});
        }
        else {
            $('#try').css({'background-color': '#0f0'});
        }
    }
    else {
        $('#try').css({'background-color': 'white'});
    }
}
$('#try').on('compositionstart', tryinput);
$('#try').on('compositionend', tryinput);
$('#try').on('compositionupdate', tryinput);
$('#try').on('change', tryinput);
$('#try').on('keyup', tryinput);
$('#try').on('keydown', tryinput);
</script>

Although, I have another example where I only required javascript code inside the field, i.e., no mix of HTML and code:

# template
<script type="text/javascript">
if(`{{Kanji}}` === `{{Radical}}`) { {{JavascriptSetAsRadical}} }
</script>

# field JavascripSetRadical
allkanji = $('.i-am-kanji'); allkanji.each(function(index, value) { // console.log(`index ${index}, ${value}...`); $(value).text('Radical'); } );

As I said before, I put them on the templates, because keeping them synced with 20 different card templates is difficult (copy and paste between all templates). That is why I add a common script and HTML button to a field and update the field with the Advanced Copy Fields addon.

It makes no sense to delete Javascript code from templates because it is the QT Chrome Web engine that parses them after Anki builds the page using the templates.

Also, this new behavior of Anki is quite troublesome as it is deleting user contents on their collection (loss of data). Please refrain from deleting user data without asking the user first.

Now I am unsure about which more code Anki has deleted from my collection. Then one I put as an example was quite simple to note because it is used quite a lot. But I am not sure if Anki deleted more data and where it did delete.

This is the code wreaking havoc, it from last year, but it was not causing trouble until this commit from last month replace the old stripHTML() methods with the backend implementation · ankitects/anki@0bb273a · GitHub came out using this everywhere:

This will reap out/clean up everybody’s collections HTML things once they install this new version of anki. I am quite unpleased by my collection having its styles and code removed out of nowhere and without any notice. Even if you noticed this was going to happen, I would not know which parts of my collection would be deleted.

I understand Anki has a feature to strip HTML code, but Anki would only strip HTML code on paste (when the user asked), instead, now Anki is trimming down everybody’s collection of any HTML it can find (definitely not cool).

Did you actually test this Evandro? The code it replaced also removed script tags, and I don’t believe it is used in field saving, so I would be a bit surprised if this change were responsible.

Are you sure it’s not anki/PlainTextInput.svelte at b9eccec2b011a8fe04dd735b4f70cc3d83a32fa9 · ankitects/anki · GitHub? @hengiesel may be able to elaborate on the reason they were removed, but I presume it was because they were causing problems. I agree that silent data loss is not good, and perhaps we should be refusing to edit the note instead.

The code in PlainTextInput should only take effect if you edit the note in the editor, and not, as evandro put it:

reap out/clean up everybody’s collections HTML things once they install this new version of anki.

@addons_zz could you confirm where the problem lies / provided a minimum repro case please?