13 Commits

Author SHA1 Message Date
def0045819 Fix the issue of incorrect JS file names introduced under Anki 23.12.1 2024-03-05 03:47:12 +08:00
6acf2d5bb5 Fix for Anki version 24.04+ 2024-03-01 16:30:31 +08:00
d6034c6dcf Fix for Anki version 24.04+ 2024-03-01 16:19:38 +08:00
65cc6c0b12 Modify the implementation method of "avoiding secondary refresh"
The previous implementation may encounter issues in specific scenarios and could potentially become invalid after Anki updates. Now, the approach has been modified to check whether the note content has been modified, which is a simpler and more understandable method.
2024-02-25 05:11:17 +08:00
8487bb86d0 Increase the setSizes parameter
If the parameter given to setSizes is very small and smaller than QSplitter, the sub windows within QSplitter will be stretched. It is advisable to set a larger parameter for setSizes as much as possible.
2024-02-02 09:12:49 +08:00
74d12576cd Fix memory leakage caused by hook not releasing
Due to Anki not providing a hook when closing the editor, refactoring to use set filter to check which editors are not active and avoid creating a large number of hooks. By traversing the set, it is determined whether the current editor needs to be refreshed.
2024-02-02 08:50:17 +08:00
deca35908a Improve compatibility with other plugins
Wrap a widget on the outer layer of the webview so that other plugins can continue to modify the layout.
2024-02-02 07:28:16 +08:00
2023cea60c Fix second refresh after loading note 2024-02-02 07:10:47 +08:00
cefa65eadf Merge pull request #20 from spacelord47/fix/use_qt6_enums_properly
All checks were successful
continuous-integration/drone/tag Build is passing
Fixes: #19 
Fixes: #18
2023-11-05 16:02:06 +01:00
766d246f46 fix: use Qt6 enums properly
New Anki version(23.10) dropped compatibility for Qt5: https://forums.ankiweb.net/t/porting-tips-for-anki-23-10/35916#enumerations-6
2023-11-05 13:53:17 +00:00
23f9c0cb68 Patch version check for new versioning scheme
I haven't taken a look at anything in the new version yet.
But that closes #16.
2023-09-25 11:50:44 +02:00
ab68523be6 Merge PR #10 2023-03-24 18:16:25 +01:00
734f24646e Remove the usage of deprecated function.
mv.pm.night_mode() is deprecated (see
1ed2cce648/qt/aqt/profiles.py (L537)).
Furthermore, on anki Version ⁨2.1.54, Python 3.9.10 Qt 6.3.1 PyQt 6.3.1, this function returns false, even when the dark mode is set.
2022-12-14 08:36:12 +01:00
2 changed files with 50 additions and 26 deletions

1
.gitignore vendored
View File

@ -117,6 +117,7 @@ venv/
ENV/ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak/
.idea
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject

View File

@ -1,4 +1,5 @@
import json import json
from typing import Set
from anki import hooks, buildinfo from anki import hooks, buildinfo
from aqt import editor, gui_hooks, mw from aqt import editor, gui_hooks, mw
@ -10,6 +11,7 @@ config = mw.addonManager.getConfig(__name__)
class EditorPreview(object): class EditorPreview(object):
editors: Set[editor.Editor] = set()
js = [ js = [
"js/mathjax.js", "js/mathjax.js",
"js/vendor/mathjax/tex-chtml.js", "js/vendor/mathjax/tex-chtml.js",
@ -19,7 +21,18 @@ class EditorPreview(object):
def __init__(self): def __init__(self):
gui_hooks.editor_did_init.append(self.editor_init_hook) gui_hooks.editor_did_init.append(self.editor_init_hook)
gui_hooks.editor_did_init_buttons.append(self.editor_init_button_hook) gui_hooks.editor_did_init_buttons.append(self.editor_init_button_hook)
if int(buildinfo.version.split(".")[2]) < 45: # < 2.1.45 gui_hooks.editor_did_load_note.append(self.editor_note_hook)
gui_hooks.editor_did_fire_typing_timer.append(self.onedit_hook)
buildversion = buildinfo.version.split(".")
# Anki changed their versioning scheme in 2023 to year.month(.patch), causing things to explode here.
if int(buildversion[0]) >= 24 or (int(buildversion[0]) == 23 and int(buildversion[1]) == 12 and 2 < len(buildversion) and int(buildversion[2])) >= 1: # >= 23.12.1
self.js = [
"js/mathjax.js",
"js/vendor/mathjax/tex-chtml-full.js",
"js/reviewer.js",
]
elif int(buildversion[0]) < 23 and int(buildversion[2]) < 45: # < 2.1.45
self.js = [ self.js = [
"js/vendor/jquery.min.js", "js/vendor/jquery.min.js",
"js/vendor/css_browser_selector.min.js", "js/vendor/css_browser_selector.min.js",
@ -42,34 +55,29 @@ class EditorPreview(object):
ed.editor_preview.hide() ed.editor_preview.hide()
self._inject_splitter(ed) self._inject_splitter(ed)
gui_hooks.editor_did_fire_typing_timer.append(lambda o: self.onedit_hook(ed, o))
gui_hooks.editor_did_load_note.append(
lambda o: None if o != ed else self.editor_note_hook(o)
)
def _get_splitter(self, editor): def _get_splitter(self, editor):
layout = editor.outerLayout mainR, editorR = [int(r) * 10000 for r in config["splitRatio"].split(":")]
mainR, editorR = [int(r) for r in config["splitRatio"].split(":")]
location = config["location"] location = config["location"]
split = QSplitter() split = QSplitter()
if location == "above": if location == "above":
split.setOrientation(Qt.Vertical) split.setOrientation(Qt.Orientation.Vertical)
split.addWidget(editor.editor_preview) split.addWidget(editor.editor_preview)
split.addWidget(editor.web) split.addWidget(editor.wrapped_web)
sizes = [editorR, mainR] sizes = [editorR, mainR]
elif location == "below": elif location == "below":
split.setOrientation(Qt.Vertical) split.setOrientation(Qt.Orientation.Vertical)
split.addWidget(editor.web) split.addWidget(editor.wrapped_web)
split.addWidget(editor.editor_preview) split.addWidget(editor.editor_preview)
sizes = [mainR, editorR] sizes = [mainR, editorR]
elif location == "left": elif location == "left":
split.setOrientation(Qt.Horizontal) split.setOrientation(Qt.Orientation.Horizontal)
split.addWidget(editor.editor_preview) split.addWidget(editor.editor_preview)
split.addWidget(editor.web) split.addWidget(editor.wrapped_web)
sizes = [editorR, mainR] sizes = [editorR, mainR]
elif location == "right": elif location == "right":
split.setOrientation(Qt.Horizontal) split.setOrientation(Qt.Orientation.Horizontal)
split.addWidget(editor.web) split.addWidget(editor.wrapped_web)
split.addWidget(editor.editor_preview) split.addWidget(editor.editor_preview)
sizes = [mainR, editorR] sizes = [mainR, editorR]
else: else:
@ -79,15 +87,31 @@ class EditorPreview(object):
return split return split
def _inject_splitter(self, editor: editor.Editor): def _inject_splitter(self, editor: editor.Editor):
layout = editor.outerLayout layout = editor.web.parentWidget().layout()
if layout is None:
layout = QVBoxLayout()
editor.web.parentWidget().setLayout(layout)
web_index = layout.indexOf(editor.web) web_index = layout.indexOf(editor.web)
layout.removeWidget(editor.web) layout.removeWidget(editor.web)
# Wrap a widget on the outer layer of the webview
# So that other plugins can continue to modify the layout
editor.wrapped_web = QWidget()
wrapLayout = QHBoxLayout()
editor.wrapped_web.setLayout(wrapLayout)
wrapLayout.addWidget(editor.web)
split = self._get_splitter(editor) split = self._get_splitter(editor)
layout.insertWidget(web_index, split) layout.insertWidget(web_index, split)
def editor_note_hook(self, editor): def editor_note_hook(self, editor):
self.onedit_hook(editor, editor.note) self.editors = set(filter(lambda it: it.note is not None, self.editors))
self.editors.add(editor)
# The initial loading of notes will also trigger an editing event
# which will cause a second refresh
# Caching the content of notes here will be used to determine if the content has changed
editor.cached_fields = list(editor.note.fields)
self.refresh(editor)
def editor_init_button_hook(self, buttons, editor): def editor_init_button_hook(self, buttons, editor):
addon_path = os.path.dirname(__file__) addon_path = os.path.dirname(__file__)
@ -111,19 +135,18 @@ class EditorPreview(object):
c = note.ephemeral_card() c = note.ephemeral_card()
a = mw.prepare_card_text_for_display(c.answer()) a = mw.prepare_card_text_for_display(c.answer())
a = gui_hooks.card_will_show(a, c, "clayoutAnswer") a = gui_hooks.card_will_show(a, c, "clayoutAnswer")
if theme_manager.night_mode: bodyclass = theme_manager.body_classes_for_card_ord(c.ord, theme_manager.night_mode)
bodyclass = theme_manager.body_classes_for_card_ord(
c.ord, mw.pm.night_mode()
)
else:
bodyclass = theme_manager.body_classes_for_card_ord(c.ord)
bodyclass += " editor-preview" bodyclass += " editor-preview"
return f"_showAnswer({json.dumps(a)},'{bodyclass}');" return f"_showAnswer({json.dumps(a)},'{bodyclass}');"
def onedit_hook(self, editor, origin): def onedit_hook(self, note):
if editor.note == origin: for editor in self.editors:
editor.editor_preview.eval(self._obtainCardText(editor.note)) if editor.note == note and editor.cached_fields != note.fields:
editor.cached_fields = list(note.fields)
self.refresh(editor)
def refresh(self, editor):
editor.editor_preview.eval(self._obtainCardText(editor.note))
eprev = EditorPreview() eprev = EditorPreview()