Shift editor control to TypeScript
Ref: https://github.com/ankitects/anki/issues/3830
Work in progress. Details to be added later.
Some tricky case you might wanna consider?
https://www.gdcdental.com/files/product/Westcott-Curved-%23-S35.jpg
because Editor._retrieveURL correctly downloads the URL but unquotes %23 to # upon return, and just assigning Westcott-Curved-#-S35.jpg to img['src'] won't work, as # act as a hash tag. It seems like it's the same on your svelte code too?
It seems like it's the same on your svelte code too?
Yes, it has the same issue. We can look into it once we're done porting & testing the existing copy & paste behavior.
@dae This is ready for some testing. Pinging @glutanimate @iamllama or anyone interested in giving feedback.
Known issues
- [x] Sticky fields not being sticky.
- [x] Misaligned sticky badge.
- [x] Fields cleared when switching note type in Add screen.
- [x] Incomplete pre-add check (
noteCanBeAdded()) - [x] Undo operations for backend calls moved to TypeScript.
- [x] Toggling MathJax preview doesn't take effect until editor is reopened: https://github.com/ankitects/anki/pull/2014
- [x] "Paste Image from Clipboard" is less reliable - it doesn't recognize files copied from Explorer on Windows but does work with images copied directly from image viewers or the web.
- [x]
navigator.clipboard.read()is a new API, so it needs testing on different platforms. - [ ] editor.parentWindow.activateWindow() removed from select_image_and_occlude and similar. I assume this is needed for macOS?
- [x] Svelte implementations for Deck and Notetype selectors.
- [ ] The elephant in the room: Add-on compatibility.
Thank you for testing @GithubAnon0000. Regarding some issues:
- (1) I think let's discuss & handle that in your PR, since the changes here are unlikely to touch that part.
- (4) This might be fixed after #4115.
- (5) Hmm, can you see this after pulling the latest changes?
- (10) Let me know if you can reproduce it in the stable version. I suspect it's a system-specific issue. What's your OS?
- (11) What's the format of the image?
Regarding 10, it was me who added the "Show in Folder" option to Anki and this option was not supposed to be shown in Linux as I don't know how to deal with the different File Managers there. I made it hidden on Linux in the Python code. Is it not hidden on Linux in the TS/Svelte code?
Answering abdnh
(1) I think let's discuss & handle that in your PR, since the changes here are unlikely to touch that part.
Got it.
(4) This might be fixed after
Indeed. On 0241113e2cde8565821d8d09cd487162285af8ba this issue is solved.
(5) Hmm, can you see this after pulling the latest changes?
Yes. I zoomed into the view to make it more apparent, but it's cut off without zoom as well:
(Please ignore the weird stripes. Anki never flawlessly worked for me, no matter which graphics driver I choose.)
- (10) Let me know if you can reproduce it in the stable version. I suspect it's a system-specific issue. What's your OS?
It doesn't happen in the stable version, as the option doesn't exist there. Probably because of what user1823 said:
"Show in Folder" option to Anki and this option was not supposed to be shown in Linux
I'm indeed on linux (debian sid).
(11) What's the format of the image?
I'm not entirely sure since I don't quite remember which cards I had tested with. Testing it now, however, reveals that it works with .png but doesn't with .svg files. Edit: .jpeg / .jpg doesn't work either.
Answering user1823
I don't know how you implemented it. But if you can call a command, then xdg-open /path/to/directory will work regardless of desktop environment / regardless of the default file manager.
@user1823
Regarding 10, it was me who added the "Show in Folder" option to Anki and this option was not supposed to be shown in Linux as I don't know how to deal with the different File Managers there. I made it hidden on Linux in the Python code. Is it not hidden on Linux in the TS/Svelte code?
Oh, yes. I forgot to hide it on Linux!
But if you can call a command, then xdg-open /path/to/directory will work regardless of desktop environment / regardless of the default file manager.
But, I can't test this. Maybe you can try your suggestion and submit a PR to fix it in the Python code? After looking through the changes in this PR, I realized that if the Python code is made to work on Linux, no additional changes will be required here.
The relevant Python code is here: https://github.com/ankitects/anki/blob/630bdd31893d5113b81cd60612cef3ebf146d5b4/qt/aqt/editor.py#L1738-L1741 https://github.com/ankitects/anki/blob/630bdd31893d5113b81cd60612cef3ebf146d5b4/qt/aqt/utils.py#L927-L941
Edit: Based on a quick Google search, it seems that xdg-open will open the image, not highlight it in the file manager. So, it won't help here.
I changed the utils.py file of this PR locally to the following:
def show_in_folder(path: str) -> None:
if is_win:
_show_in_folder_win32(path)
elif is_mac:
script = f"""
tell application "Finder"
activate
select POSIX file "{path}"
end tell
"""
call(osascript_to_args(script))
else:
subprocess.run(["xdg-open", path])
# Just open the file in any other platform
#with no_bundled_libs():
# QDesktopServices.openUrl(QUrl.fromLocalFile(path))
It opens my file manager (nautilus / gnome files) and does highlight the correct image.
I cannot suggest this change in this PR, since github won't let me. I'll open a separate PR.
Thanks for this, it's going to make working on the editor much faster! Noticed a few additional issues as well:
- The add window now flashes like the stats window, maybe setting the webview bg colour to canvas would help here
- The "Copy", "Cut" and "Paste" context menu actions don't seem to work on win 10 or wsl for me
- On dark mode, the context menu's text is white
- "Discard changes" shows when trying to close after adding a note
- "Create copy" seems to be broken as well, but differently depending on the notetype
- Cloze notes: clicking in and out of a field shows an error. On the console it prints
JS error /_app/immutable/chunks/BjIIu02o.mjs:2 Uncaught (in promise) Error(no AnkiWebView Inspector :/) - IO notes: the editor loads and shows the masks/image, but is otherwise not functional (can't change tool)
- Other types: fields are just blank
- Cloze notes: clicking in and out of a field shows an error. On the console it prints
- ~~When adding cloze notes without any clozes, the
You have a cloze notetype but have not made any cloze deletions. Proceed?dialog doesn't appear anymore. Clicking on theAddbutton just does nothing until a cloze is added~~ - ~~"The first field is empty" dialog doesn't show either (related to 6.)~~
- When in the browser with a selected row and holding "Down", an error dialog is sometimes shown. When closed (or when the "Down" key is released if no error), the editor appears to rapidly cycle through each note before stopping at the last row when instead it should be debounced
Haven't been able to go through all the commits yet, will get to it when possible!
tatsumoto-ren posted the following in #3830:
Rewriting the editor in pure Qt will achieve the following:
[…]
- Will work fast unlike the Electron-like experience we have today.
[…]
Is there a way to benchmark this and check which version (current implementation or implementation from this PR) is faster? I'd imagine the performance shouldn't be too bad with svelte, typescript, … considering the views that would be opened are low complexity and not many things run in parallel anyways.
the performance shouldn't be too bad
If you compare webview windows with pure-Qt windows in Anki, you'll notice that Qt windows appear instantly, while webviews can take nearly half a second, or even close to a full second, to load. The worst example is the "deck options" dialog, which used to perform much better in the past and had a more minimalist design.
I think we can now confidently say that continuing to rely on webviews will negatively impact performance and the overall user experience.
just fyi, dae once said
While we load a separate HTML page for each feature, things are going to be a bit slower than native code. Later on once we can start reducing the number of separate webviews, loading performance should improve.
Hope one day we get a pure electron-based webapp of Anki that we can also access on https://ankiweb.net/
That'll probably never happen given AnkiWeb is strategically designed to not blow up AnkiMobile sales.
If this code moves all editor-related code to typescript, what API's will be exposed to allow custom buttons?
def add_buttons(buttons: List[str], editor: Editor) -> None:
shortcut = "Ctrl+Alt+Shift+H"
def _(editor: Editor) -> None:
editor.web.eval("setFormat('inserthtml', '<img src=_cha_cha-enable.png>');")
buttons.append(
editor.addButton(
icon=None,
cmd=f"add_cloze_hide_all_marker",
func=_,
tip="Make this note like 'Cloze (Hide All)'",
label="█ CHA",
keys=shortcut,
)
)
gui_hooks.editor_did_init_buttons.append(add_buttons)
For example, how should I port this code?
@phu54321 editor.addButton() will keep working. Most editor hooks are broken in this PR right now though, and we still need to think about reducing add-on breakages (and probably introduce a JS API).
Very excited to see the progress here @abdnh! Hope to have this properly reviewed by the end of the week.
That'll probably never happen given AnkiWeb is strategically designed to not blow up AnkiMobile sales.
While there is an aspect of that, another significant concern is who will pay for the server resources. CPU or I/O-costly features cost us nothing to run on user's own computers, but that's not the case for a hosted service.
tatsumoto-ren posted the following in https://github.com/ankitects/anki/issues/3830#issuecomment-3006354480:
Rewriting the editor in pure Qt will achieve the following:
I've moved that to https://github.com/ankitects/anki/issues/4142 so we keep this PR on topic.
Sorry it's taken me a while to circle back to this Abdo. I'm going to start reading through the changes and start testing on iOS so I can get up to speed with things.
The elephant in the room: Add-on compatibility.
We'll of course want to do what we can here, but I presume there'll be some workflows that can't be easily adapted. I think our best path forward here might be to have a transitionary period where the old and new screens are both available and can be switched between, like as talked about on https://github.com/ankitects/anki/issues/2474#issuecomment-1510775549. That will allow us to iterate on this after the initial merge without any immediate impact on users, and reduces the pressure on us to get this perfect from the start.
The changes in editor.py look fairly extensive, and it may be easiest to copy in a version of the file prior to the changes. For the other files like editcurrent.py, having separate code paths for the two cases might be simplest? For the TS side, you probably have a better idea of whether it would make sense to clone some of the files, the entire ts/editor, or add separate code paths to the existing files. WDYT?
It will be a bit of a pain to make both the old and new approach work at once, and will leave the codebase in a messier state. I'm hoping that it's something we'd have in place for <6 months, not for years like the old deck options/stats screens, as it's too much code to try and maintain multiple copies of for long periods.
Preserving the git history of your changes is more important than the legacy codepath, so I think it might make more sense to put any copies of the old code we make in a new file, rather than copying your changes into a new file (then importing them into the old location so add-ons still find things at the old location). But other ideas welcome.
Will trickle in some more comments as I go through this.
Since these changes negatively impact the user experience on desktop, it would be better if they were implemented in an add-on instead. Alternatively, there should be a way to completely and permanently opt out of them. I'm not a fan of transition periods, as they don’t solve the problem, they only postpone it.
https://github.com/ankitects/anki/issues/4142#issuecomment-3059469064
That will allow us to iterate on this after the initial merge without any immediate impact on users, and reduces the pressure on us to get this perfect from the start.
That's reasonable. I was worried figuring out add-on compatibility would take a lot of time and discussions.
The changes in editor.py look fairly extensive, and it may be easiest to copy in a version of the file prior to the changes. For the other files like editcurrent.py, having separate code paths for the two cases might be simplest? For the TS side, you probably have a better idea of whether it would make sense to clone some of the files, the entire ts/editor, or add separate code paths to the existing files. WDYT?
I agree it will be simpler to have separate Python files for the new code. For the TS side, most of my changes consist of replacing bridgeCommand() calls with a backend call and some logic ported from Python. As there's not much change to the code flow, I feel the simplest option to add a legacy switch to existing code to make it go back to bridgeCommand handling.
This looks like the old Anki window.
I guess this PR is to resolve future technical debt, but I think this could be re-implementing some other WYSIWYG toolkits like summernote or tinymce.
I once used Summernote for making kian, so maybe you can look at it. Better to avoid reinventing the wheels?
https://ankiweb.net/shared/info/805891399 this addon uses tinymce, but I heard it has some licensing issues.
I guess this PR is to resolve future technical debt, but I think this could be re-implementing some other WYSIWYG toolkits like summernote or tinymce.
This is out of the scope of this PR, but it's tracked here: https://github.com/ankitects/anki/issues/3836