mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
Inject bridge script when profile set-up skipped
Some add-ons fully override AnkiWebPage.__init__ and thus depend on _setupBridge injecting the JS bridge script.
With this change we account for these cases, while giving add-ons the opportunity to look for solutions that do not require overriding AnkiWebPage.__init__ completely.
(cherry picked from commit 2a97b135ee
)
This commit is contained in:
parent
0467f717ad
commit
269fb073e9
1 changed files with 59 additions and 36 deletions
|
@ -73,44 +73,7 @@ class AuthInterceptor(QWebEngineUrlRequestInterceptor):
|
||||||
info.setHttpHeader(b"Authorization", f"Bearer {_APIKEY}".encode("utf-8"))
|
info.setHttpHeader(b"Authorization", f"Bearer {_APIKEY}".encode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
_profile_with_api_access: QWebEngineProfile | None = None
|
def _create_bridge_script() -> QWebEngineScript:
|
||||||
_profile_without_api_access: QWebEngineProfile | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class AnkiWebPage(QWebEnginePage):
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
onBridgeCmd: BridgeCommandHandler,
|
|
||||||
kind: AnkiWebViewKind = AnkiWebViewKind.DEFAULT,
|
|
||||||
parent: QObject | None = None,
|
|
||||||
) -> None:
|
|
||||||
profile = self._profileForPage(kind)
|
|
||||||
QWebEnginePage.__init__(self, profile, parent)
|
|
||||||
self._onBridgeCmd = onBridgeCmd
|
|
||||||
self._kind = kind
|
|
||||||
self._setupBridge()
|
|
||||||
self.open_links_externally = True
|
|
||||||
|
|
||||||
def _profileForPage(self, kind: AnkiWebViewKind) -> QWebEngineProfile:
|
|
||||||
have_api_access = kind in (
|
|
||||||
AnkiWebViewKind.DECK_OPTIONS,
|
|
||||||
AnkiWebViewKind.EDITOR,
|
|
||||||
AnkiWebViewKind.DECK_STATS,
|
|
||||||
AnkiWebViewKind.CHANGE_NOTETYPE,
|
|
||||||
AnkiWebViewKind.BROWSER_CARD_INFO,
|
|
||||||
)
|
|
||||||
|
|
||||||
global _profile_with_api_access, _profile_without_api_access
|
|
||||||
|
|
||||||
# Use cached profile if available
|
|
||||||
if have_api_access and _profile_with_api_access is not None:
|
|
||||||
return _profile_with_api_access
|
|
||||||
elif not have_api_access and _profile_without_api_access is not None:
|
|
||||||
return _profile_without_api_access
|
|
||||||
|
|
||||||
# Create a new profile if not cached
|
|
||||||
profile = QWebEngineProfile()
|
|
||||||
|
|
||||||
qwebchannel = ":/qtwebchannel/qwebchannel.js"
|
qwebchannel = ":/qtwebchannel/qwebchannel.js"
|
||||||
jsfile = QFile(qwebchannel)
|
jsfile = QFile(qwebchannel)
|
||||||
if not jsfile.open(QIODevice.OpenModeFlag.ReadOnly):
|
if not jsfile.open(QIODevice.OpenModeFlag.ReadOnly):
|
||||||
|
@ -143,9 +106,49 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady)
|
script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady)
|
||||||
script.setRunsOnSubFrames(False)
|
script.setRunsOnSubFrames(False)
|
||||||
|
|
||||||
scripts = profile.scripts()
|
return script
|
||||||
assert scripts is not None
|
|
||||||
scripts.insert(script)
|
|
||||||
|
_bridge_script = _create_bridge_script()
|
||||||
|
|
||||||
|
_profile_with_api_access: QWebEngineProfile | None = None
|
||||||
|
_profile_without_api_access: QWebEngineProfile | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class AnkiWebPage(QWebEnginePage):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
onBridgeCmd: BridgeCommandHandler,
|
||||||
|
kind: AnkiWebViewKind = AnkiWebViewKind.DEFAULT,
|
||||||
|
parent: QObject | None = None,
|
||||||
|
) -> None:
|
||||||
|
profile = self._profileForPage(kind)
|
||||||
|
self._inject_user_script(profile, _bridge_script)
|
||||||
|
QWebEnginePage.__init__(self, profile, parent)
|
||||||
|
self._onBridgeCmd = onBridgeCmd
|
||||||
|
self._kind = kind
|
||||||
|
self._setupBridge()
|
||||||
|
self.open_links_externally = True
|
||||||
|
|
||||||
|
def _profileForPage(self, kind: AnkiWebViewKind) -> QWebEngineProfile:
|
||||||
|
have_api_access = kind in (
|
||||||
|
AnkiWebViewKind.DECK_OPTIONS,
|
||||||
|
AnkiWebViewKind.EDITOR,
|
||||||
|
AnkiWebViewKind.DECK_STATS,
|
||||||
|
AnkiWebViewKind.CHANGE_NOTETYPE,
|
||||||
|
AnkiWebViewKind.BROWSER_CARD_INFO,
|
||||||
|
)
|
||||||
|
|
||||||
|
global _profile_with_api_access, _profile_without_api_access
|
||||||
|
|
||||||
|
# Use cached profile if available
|
||||||
|
if have_api_access and _profile_with_api_access is not None:
|
||||||
|
return _profile_with_api_access
|
||||||
|
elif not have_api_access and _profile_without_api_access is not None:
|
||||||
|
return _profile_without_api_access
|
||||||
|
|
||||||
|
# Create a new profile if not cached
|
||||||
|
profile = QWebEngineProfile()
|
||||||
|
|
||||||
interceptor = AuthInterceptor(profile, api_enabled=have_api_access)
|
interceptor = AuthInterceptor(profile, api_enabled=have_api_access)
|
||||||
profile.setUrlRequestInterceptor(interceptor)
|
profile.setUrlRequestInterceptor(interceptor)
|
||||||
|
@ -157,6 +160,19 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
return profile
|
return profile
|
||||||
|
|
||||||
def _setupBridge(self) -> None:
|
def _setupBridge(self) -> None:
|
||||||
|
# Add-on compatibility: For existing add-on callers that override the init
|
||||||
|
# and invoke _setupBridge directly (e.g. in order to use a custom web profile),
|
||||||
|
# we need to ensure that the bridge script is injected into the profile scripts,
|
||||||
|
# if it has yet to be injected.
|
||||||
|
profile = self.profile()
|
||||||
|
assert profile is not None
|
||||||
|
scripts = profile.scripts()
|
||||||
|
assert scripts is not None
|
||||||
|
|
||||||
|
if not scripts.contains(_bridge_script):
|
||||||
|
print("add-on callers should not call _setupBridge directly")
|
||||||
|
self._inject_user_script(profile, _bridge_script)
|
||||||
|
|
||||||
class Bridge(QObject):
|
class Bridge(QObject):
|
||||||
def __init__(self, bridge_handler: Callable[[str], Any]) -> None:
|
def __init__(self, bridge_handler: Callable[[str], Any]) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -172,6 +188,13 @@ class AnkiWebPage(QWebEnginePage):
|
||||||
self._channel.registerObject("py", self._bridge)
|
self._channel.registerObject("py", self._bridge)
|
||||||
self.setWebChannel(self._channel)
|
self.setWebChannel(self._channel)
|
||||||
|
|
||||||
|
def _inject_user_script(
|
||||||
|
self, profile: QWebEngineProfile, script: QWebEngineScript
|
||||||
|
) -> None:
|
||||||
|
scripts = profile.scripts()
|
||||||
|
assert scripts is not None
|
||||||
|
scripts.insert(script)
|
||||||
|
|
||||||
def javaScriptConsoleMessage(
|
def javaScriptConsoleMessage(
|
||||||
self,
|
self,
|
||||||
level: QWebEnginePage.JavaScriptConsoleMessageLevel,
|
level: QWebEnginePage.JavaScriptConsoleMessageLevel,
|
||||||
|
|
Loading…
Reference in a new issue