diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py
index d28c8295c..9c5babb43 100644
--- a/qt/aqt/deckbrowser.py
+++ b/qt/aqt/deckbrowser.py
@@ -5,6 +5,7 @@
from __future__ import annotations
from copy import deepcopy
+from dataclasses import dataclass
from typing import Any
import aqt
@@ -32,6 +33,22 @@ class DeckBrowserBottomBar:
self.deck_browser = deck_browser
+@dataclass
+class DeckBrowserContent:
+ """Stores sections of HTML content that the deck browser will be
+ populated with.
+
+ Attributes:
+ tree {str} -- HTML of the deck tree section
+ stats {str} -- HTML of the stats section
+ countwarn {str} -- HTML of the deck count warning section
+ """
+
+ tree: str
+ stats: str
+ countwarn: str
+
+
class DeckBrowser:
_dueTree: Any
@@ -112,10 +129,14 @@ class DeckBrowser:
gui_hooks.deck_browser_did_render(self)
def __renderPage(self, offset):
- tree = self._renderDeckTree(self._dueTree)
- stats = self._renderStats()
+ content = DeckBrowserContent(
+ tree=self._renderDeckTree(self._dueTree),
+ stats=self._renderStats(),
+ countwarn=self._countWarn(),
+ )
+ gui_hooks.deck_browser_will_render_content(self, content)
self.web.stdHtml(
- self._body % dict(tree=tree, stats=stats, countwarn=self._countWarn()),
+ self._body % content.__dict__,
css=["deckbrowser.css"],
js=["jquery.js", "jquery-ui.js", "deckbrowser.js"],
context=self,
diff --git a/qt/aqt/gui_hooks.py b/qt/aqt/gui_hooks.py
index b9fc915b4..26d6de196 100644
--- a/qt/aqt/gui_hooks.py
+++ b/qt/aqt/gui_hooks.py
@@ -435,6 +435,63 @@ class _DeckBrowserDidRenderHook:
deck_browser_did_render = _DeckBrowserDidRenderHook()
+class _DeckBrowserWillRenderContentHook:
+ """Used to modify HTML content sections in the deck browser body
+
+ 'content' contains the sections of HTML content the deck browser body
+ will be updated with.
+
+ When modifying the content of a particular section, please make sure your
+ changes only perform the minimum required edits to make your add-on work.
+ You should avoid overwriting or interfering with existing data as much
+ as possible, instead opting to append your own changes, e.g.:
+
+ def on_deck_browser_will_render_content(deck_browser, content):
+ content.stats += "
+
my html
"
+ """
+
+ _hooks: List[
+ Callable[
+ ["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
+ ]
+ ] = []
+
+ def append(
+ self,
+ cb: Callable[
+ ["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
+ ],
+ ) -> None:
+ """(deck_browser: aqt.deckbrowser.DeckBrowser, content: aqt.deckbrowser.DeckBrowserContent)"""
+ self._hooks.append(cb)
+
+ def remove(
+ self,
+ cb: Callable[
+ ["aqt.deckbrowser.DeckBrowser", "aqt.deckbrowser.DeckBrowserContent"], None
+ ],
+ ) -> None:
+ if cb in self._hooks:
+ self._hooks.remove(cb)
+
+ def __call__(
+ self,
+ deck_browser: aqt.deckbrowser.DeckBrowser,
+ content: aqt.deckbrowser.DeckBrowserContent,
+ ) -> None:
+ for hook in self._hooks:
+ try:
+ hook(deck_browser, content)
+ except:
+ # if the hook fails, remove it
+ self._hooks.remove(hook)
+ raise
+
+
+deck_browser_will_render_content = _DeckBrowserWillRenderContentHook()
+
+
class _DeckBrowserWillShowOptionsMenuHook:
_hooks: List[Callable[[QMenu, int], None]] = []
@@ -772,6 +829,55 @@ class _OverviewDidRefreshHook:
overview_did_refresh = _OverviewDidRefreshHook()
+class _OverviewWillRenderContentHook:
+ """Used to modify HTML content sections in the overview body
+
+ 'content' contains the sections of HTML content the overview body
+ will be updated with.
+
+ When modifying the content of a particular section, please make sure your
+ changes only perform the minimum required edits to make your add-on work.
+ You should avoid overwriting or interfering with existing data as much
+ as possible, instead opting to append your own changes, e.g.:
+
+ def on_overview_will_render_content(overview, content):
+ content.table += "
+my html
"
+ """
+
+ _hooks: List[
+ Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None]
+ ] = []
+
+ def append(
+ self,
+ cb: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None],
+ ) -> None:
+ """(overview: aqt.overview.Overview, content: aqt.overview.OverviewContent)"""
+ self._hooks.append(cb)
+
+ def remove(
+ self,
+ cb: Callable[["aqt.overview.Overview", "aqt.overview.OverviewContent"], None],
+ ) -> None:
+ if cb in self._hooks:
+ self._hooks.remove(cb)
+
+ def __call__(
+ self, overview: aqt.overview.Overview, content: aqt.overview.OverviewContent
+ ) -> None:
+ for hook in self._hooks:
+ try:
+ hook(overview, content)
+ except:
+ # if the hook fails, remove it
+ self._hooks.remove(hook)
+ raise
+
+
+overview_will_render_content = _OverviewWillRenderContentHook()
+
+
class _ProfileDidOpenHook:
_hooks: List[Callable[[], None]] = []
diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py
index e94b69953..4184660e1 100644
--- a/qt/aqt/overview.py
+++ b/qt/aqt/overview.py
@@ -4,6 +4,8 @@
from __future__ import annotations
+from dataclasses import dataclass
+
import aqt
from anki.lang import _
from aqt import gui_hooks
@@ -17,6 +19,24 @@ class OverviewBottomBar:
self.overview = overview
+@dataclass
+class OverviewContent:
+ """Stores sections of HTML content that the overview will be
+ populated with.
+
+ Attributes:
+ deck {str} -- Plain text deck name
+ shareLink {str} -- HTML of the share link section
+ desc {str} -- HTML of the deck description section
+ table {str} -- HTML of the deck stats table section
+ """
+
+ deck: str
+ shareLink: str
+ desc: str
+ table: str
+
+
class Overview:
"Deck overview."
@@ -141,14 +161,15 @@ class Overview:
shareLink = 'Reviews and Updates'
else:
shareLink = ""
+ content = OverviewContent(
+ deck=deck["name"],
+ shareLink=shareLink,
+ desc=self._desc(deck),
+ table=self._table(),
+ )
+ gui_hooks.overview_will_render_content(self, content)
self.web.stdHtml(
- self._body
- % dict(
- deck=deck["name"],
- shareLink=shareLink,
- desc=self._desc(deck),
- table=self._table(),
- ),
+ self._body % content.__dict__,
css=["overview.css"],
js=["jquery.js", "overview.js"],
context=self,
diff --git a/qt/tools/genhooks_gui.py b/qt/tools/genhooks_gui.py
index cd2c8d471..c71917407 100644
--- a/qt/tools/genhooks_gui.py
+++ b/qt/tools/genhooks_gui.py
@@ -25,11 +25,51 @@ hooks = [
doc="""Allow to update the overview window. E.g. add the deck name in the
title.""",
),
+ Hook(
+ name="overview_will_render_content",
+ args=[
+ "overview: aqt.overview.Overview",
+ "content: aqt.overview.OverviewContent",
+ ],
+ doc="""Used to modify HTML content sections in the overview body
+
+ 'content' contains the sections of HTML content the overview body
+ will be updated with.
+
+ When modifying the content of a particular section, please make sure your
+ changes only perform the minimum required edits to make your add-on work.
+ You should avoid overwriting or interfering with existing data as much
+ as possible, instead opting to append your own changes, e.g.:
+
+ def on_overview_will_render_content(overview, content):
+ content.table += "\nmy html
"
+ """,
+ ),
Hook(
name="deck_browser_did_render",
args=["deck_browser: aqt.deckbrowser.DeckBrowser"],
doc="""Allow to update the deck browser window. E.g. change its title.""",
),
+ Hook(
+ name="deck_browser_will_render_content",
+ args=[
+ "deck_browser: aqt.deckbrowser.DeckBrowser",
+ "content: aqt.deckbrowser.DeckBrowserContent",
+ ],
+ doc="""Used to modify HTML content sections in the deck browser body
+
+ 'content' contains the sections of HTML content the deck browser body
+ will be updated with.
+
+ When modifying the content of a particular section, please make sure your
+ changes only perform the minimum required edits to make your add-on work.
+ You should avoid overwriting or interfering with existing data as much
+ as possible, instead opting to append your own changes, e.g.:
+
+ def on_deck_browser_will_render_content(deck_browser, content):
+ content.stats += "\nmy html
"
+ """,
+ ),
Hook(
name="reviewer_did_show_question",
args=["card: Card"],