mirror of
https://github.com/ankitects/anki.git
synced 2026-01-10 04:23:54 -05:00
Added: Monkey patch localStorage solution
This commit is contained in:
parent
834c2b9a75
commit
6b0b2aad56
5 changed files with 90 additions and 6 deletions
|
|
@ -723,6 +723,8 @@ exposed_backend_list = [
|
|||
# CollectionService
|
||||
"latest_progress",
|
||||
"get_custom_colours",
|
||||
"set_config_json",
|
||||
"get_config_json",
|
||||
# DeckService
|
||||
"get_deck_names",
|
||||
# I18nService
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,4 +7,9 @@ interface HtmlMessage {
|
|||
bodyclass?: string;
|
||||
}
|
||||
|
||||
export type InnerReviewerRequest = HtmlMessage;
|
||||
interface StorageUpdateMessage {
|
||||
type: "setstorage";
|
||||
json_buffer: Uint8Array;
|
||||
}
|
||||
|
||||
export type InnerReviewerRequest = HtmlMessage | StorageUpdateMessage;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue