Added: Monkey patch localStorage solution

This commit is contained in:
Luc Mcgrady 2025-11-07 15:48:14 +00:00
parent 834c2b9a75
commit 6b0b2aad56
No known key found for this signature in database
GPG key ID: 4F3D7A0B17CC3D9C
5 changed files with 90 additions and 6 deletions

View file

@ -723,6 +723,8 @@ exposed_backend_list = [
# CollectionService
"latest_progress",
"get_custom_colours",
"set_config_json",
"get_config_json",
# DeckService
"get_deck_names",
# I18nService

View file

@ -17,12 +17,17 @@ function postParentMessage(message: ReviewerRequest) {
declare const MathJax: any;
const urlParams = new URLSearchParams(location.search);
const decoder = new TextDecoder();
const style = document.createElement("style");
document.head.appendChild(style);
addEventListener("message", async (e: MessageEvent<InnerReviewerRequest>) => {
switch (e.data.type) {
case "setstorage": {
const json = JSON.parse(decoder.decode(e.data.json_buffer));
Object.assign(storageObj, json);
break;
}
case "html": {
document.body.innerHTML = e.data.value;
if (e.data.css) {
@ -56,7 +61,7 @@ addEventListener("message", async (e: MessageEvent<InnerReviewerRequest>) => {
break;
}
default: {
console.warn(`Unknown message type: ${e.data.type}`);
// console.warn(`Unknown message type: ${e.data.type}`);
break;
}
}
@ -99,3 +104,61 @@ function _typeAnsPress() {
);
}
globalThis._typeAnsPress = _typeAnsPress;
const storageObj = {};
const encoder = new TextEncoder();
function updateParentStorage() {
postParentMessage({ type: "setstorage", json_buffer: encoder.encode(JSON.stringify(storageObj)) });
}
function createStorageProxy() {
return new Proxy({}, {
get(_target, prop) {
switch (prop) {
case "getItem":
return (key) => key in storageObj ? storageObj[key] : null;
case "setItem":
return (key, value) => {
storageObj[key] = String(value);
updateParentStorage();
};
case "removeItem":
return (key) => {
delete storageObj[key];
updateParentStorage();
};
case "clear":
return () => {
Object.keys(storageObj).forEach(key => delete storageObj[key]);
updateParentStorage();
};
case "key":
return (index) => Object.keys(storageObj)[index] ?? null;
case "length":
return Object.keys(storageObj).length;
default:
return storageObj[prop];
}
},
set(_target, prop, value) {
storageObj[prop] = String(value);
return true;
},
ownKeys() {
return Object.keys(storageObj);
},
getOwnPropertyDescriptor(_target, _prop) {
return { enumerable: true, configurable: true };
},
});
}
const ankiStorage = createStorageProxy();
Object.defineProperty(window, "localStorage", {
value: ankiStorage,
writable: false,
configurable: true,
enumerable: true,
});

View file

@ -7,4 +7,9 @@ interface HtmlMessage {
bodyclass?: string;
}
export type InnerReviewerRequest = HtmlMessage;
interface StorageUpdateMessage {
type: "setstorage";
json_buffer: Uint8Array;
}
export type InnerReviewerRequest = HtmlMessage | StorageUpdateMessage;

View file

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { CardAnswer, type NextCardDataResponse_NextCardData } from "@generated/anki/scheduler_pb";
import { compareAnswer, nextCardData, playAvtags } from "@generated/backend";
import { compareAnswer, getConfigJson, nextCardData, playAvtags, setConfigJson } from "@generated/backend";
import { derived, get, writable } from "svelte/store";
import type { InnerReviewerRequest } from "../reviewer-inner/innerReviewerRequest";
import type { ReviewerRequest } from "./reviewerRequest";
@ -39,8 +39,10 @@ export class ReviewerState {
iframe: HTMLIFrameElement | undefined = undefined;
onReady() {
async onReady() {
this.iframe!.style.visibility = "visible";
const { json } = await getConfigJson({ val: "reviewer_storage" });
this.sendInnerRequest({ type: "setstorage", json_buffer: json });
this.showQuestion(null);
addEventListener("message", this.onMessage.bind(this));
}
@ -60,6 +62,13 @@ export class ReviewerState {
this.handleKeyPress(e.data.key);
break;
}
case "setstorage": {
setConfigJson({
key: "reviewer_storage",
valueJson: e.data.json_buffer,
undoable: false,
});
}
}
}

View file

@ -16,4 +16,9 @@ interface KeyPressMessage {
key: string;
}
export type ReviewerRequest = AudioMessage | UpdateTypedAnswerMessage | KeyPressMessage;
interface SetStorageMessage {
type: "setstorage";
json_buffer: Uint8Array;
}
export type ReviewerRequest = AudioMessage | UpdateTypedAnswerMessage | KeyPressMessage | SetStorageMessage;