javascript - JavaScript 在 Anki 2.0 版本中有效,但在 2.1 版本中无效
问题描述
我正在使用 Anki 帮助我五年级的儿子学习数学。我儿子已经到了需要复习如何处理具体问题而不是简单地记住事实的地步。
例如,假设您正在尝试学习如何将分数相乘... .45 X .61 = ?
我需要一种将随机数学问题放入 Anki 卡片的方法。这意味着有一天卡片会显示 .45 X .61 = ? 下次显示卡片时,问题可能是.. .34 X .12 = ?
在网上搜索之后,我找到了一篇解释如何做到这一点的文章......
https://yingtongli.me/blog/2015/03/15/random-question-generator-on-anki-using.html
我不是 JavaScript 开发人员,但在我用头敲击键盘一周后,我能够让这项技术发挥作用。
让我解释一下你是如何做到这一点的,然后我会解释问题出在哪里。
安装 Anki 2.0 版本。
打开 Anki 并创建一个新牌组。
将一张新卡添加到套牌中。
出现添加卡对话框。最顶部是两个长按钮……“Type”和“Deck”。单击左侧的“类型”按钮。
出现选择注释类型对话框。
单击对话框底部的“管理”按钮。
选择基本注释类型,然后单击左侧的“添加”按钮。
第一个选项应该是“添加基本”。单击对话框底部的“确定”按钮。
命名您的新笔记类型..“脚本笔记类型”,然后单击“确定”
命中逃跑。
现在选择您的新注释类型(“脚本注释类型”),然后单击“选择”。
现在我们要添加一个额外的字段。默认情况下,此注释类型具有名为“Front”和“Back”的字段。我们要添加名为“脚本”的第三个字段。
左上角附近有一个标有“字段”的按钮。单击此按钮。
出现另一个对话框。左侧是一个添加按钮。点击它。
在出现的对话框中输入脚本,然后单击“确定”按钮。
现在通过单击右侧按钮附近的关闭按钮关闭当前对话框。
现在让我们设置卡片。当前屏幕的左上角附近有两个按钮。右侧的按钮标有“卡片”。单击此按钮。
这是我们设置卡片模板的地方。JavaScript 代码的一部分进入前端模板。目前这里应该有以下文字...
{{正面}}
删除所有内容并粘贴以下代码。
<script>
function persist(cb) {
window.setTimeout(function() {
// Determine whether to use Anki's Bridge object (Desktop) or sessionStorage (AnkiDroid) to store data across sides.
var dummy = {};
var mode = "dummy";
if (typeof(py) !== "undefined") {
mode = "py";
py.data = py.data || {};
} else if (typeof(sessionStorage) !== "undefined") {
mode = "sessionStorage";
}
var dataObj = {
setItem: function(key, val) {
if (mode === "dummy") {
dummy[key] = val;
} else if (mode === "py") {
py.data[key] = val;
} else if (mode === "sessionStorage") {
sessionStorage.setItem(key, val);
}
},
getItem: function(key, def) {
var val = undefined;
if (mode === "dummy") {
val = dummy[key];
} else if (mode === "py") {
val = py.data[key];
} else if (mode === "sessionStorage") {
val = sessionStorage.getItem(key);
}
if (val == null) {
return def;
} else {
return val;
}
},
tryItem: function(key, val) {
var currVal = dataObj.getItem(key, undefined);
if (currVal == null) {
dataObj.setItem(key, val);
return val;
} else {
return currVal;
}
},
clear: function() {
if (mode === "dummy") {
dummy = {};
} else if (mode === "py") {
window.py.data = {};
} else if (mode === "sessionStorage") {
sessionStorage.clear();
}
}
};
if (!document.getElementById("back")) {
dataObj.clear();
}
cb(dataObj);
}, 0); //Execute after Anki has loaded its Bridge object.
}
</script>
<script>
var code = (function () {/* {{Script}} */}).toString();
code = code.replace(/^[^\/]+\/\*!?/, "").replace(/\*\/[^\/]+$/, ""); //Strip beginning/ending comments.
code = code.replace(/<div>/g, "\n").replace(/<\/div>/g, "\n").replace(/<br \/>/g, "\n"); //Strip HTML.
code = code.replace(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&"); //Replace special symbols.
eval(code);
</script>
<div id="front">{{Front}}</div>
此 JavaScript 采用我们将放置在“脚本”字段中的 JavaScrippt 代码并使用 eval 语句执行它。
请注意,在这段代码中,persist 函数使 Anki 卡的正面和背面之间的值保持一致。我的问题与此持久功能有关。
在屏幕底部三分之一处是一个“返回模板”。删除所有内容并粘贴以下代码...
{{FrontSide}}
<hr id=answer>
<div id="back">{{Back}}</div>
点击右下角的“关闭”按钮。
现在我们需要填写这些字段。前面和后面的值无关紧要。我把“Front”放在前面,“Back”放在后面。
对于 Script 字段,我们要添加一些代码。在粘贴代码之前,我们需要打开 HTML 视图。确保您的光标位于脚本字段中。
在 Anki 2.0 版本中,屏幕右上方有一个带有向下箭头图片的按钮。2.1 版本有“...”而不是向下箭头按钮。
单击此箭头,将出现一个菜单。选择“编辑 HTML”菜单选项。
粘贴以下代码...
window.setTimeout(function(){
persist(function(data) {
var num1 = data.tryItem("num1",Math.random());
document.getElementById("front").innerHTML = num1;
document.getElementById("back").innerHTML = num1;
});
},0);
这适用于 Anki 2.0 版本。
这是问题
这是答案...
我们在 JavaScript 中生成了一个随机数,该值保存在 Anki Card 的正面和背面之间。这为使用随机数的数学和科学 Anki 卡片开辟了无限可能。
然而,Whoville 的情况并不好。
当您在 Anki 2.1 版本上运行此代码时,它不起作用。
绕过脚本并显示 Front 和 Back 字段的静态值。
JavaScript 仍在执行中。我可以在 Script 字段中放置一条警告语句,它可以工作。
问题出在 Persist 函数中。较新版本的 Anki 不喜欢 Persist 功能。
谁能指出我正确的方向。
解决方案
我想到了...
问题是 Anki 2.1 取消了在 window.py 对象中存储持久数据的能力。
现在你可能会问(和我一样)window.py 对象是什么?我不是 100% 确定,但我相信它是一个内部 Python 对象,它允许 JavaScript 和 Python 之间进行一些交互。Anki 是用 Python 编写的。
无论如何,在 Anki 2.1 中不再可以访问 window.py,这意味着我在问题中描述的技术(见上文)不再适用于 Anki 2.1。
幸运的是,文章的作者(在上面的问题中引用了)提到窗口对象在 Anki 卡片问题和答案的调用之间是共享的。
我开始在 Javascript 中使用 window 对象,并且能够在 Anki 2.1 中获得数据持久性(这也适用于 Anki 2.0)
在上面的问题中,我深入研究了这种在 Anki 卡片中生成持久随机值的技术。这意味着您在问题中生成一个随机数,并且答案中提供相同的值。我不会在这里详细介绍,但请参阅上面的问题以获取更多详细信息。
在“前端模板”中,这里是代码。
<script>
var code = (function () {/* {{Script}} */}).toString();
code = code.replace(/^[^\/]+\/\*!?/, "").replace(/\*\/[^\/]+$/, ""); //Strip beginning/ending comments.
code = code.replace(/<div>/g, "\n").replace(/<\/div>/g, "\n").replace(/<br \/>/g, "\n"); //Strip HTML.
code = code.replace(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&"); //Replace special symbols.
eval(code);
</script>
<div id="front">{{Front}}</div>
这与文章中的代码相同。我只是删除了一些不再有效的代码。
这是卡片脚本代码...
window.setTimeout(function(){
var windowsref = window; //Set a reference to the window object
if ((("num1" in windowsref) == false) || windowsref.cnt != 1) {
windowsref.num1 = Math.random();
windowsref.cnt = 0;
}
windowsref.cnt++;
document.getElementById("front").innerHTML = windowsref.num1;
document.getElementById("back").innerHTML = windowsref.num1;
},0);
此代码仅适用于 Anki 2.1 桌面。我还测试了 iOS,它也可以在那里工作。
我希望这对其他人有帮助。
推荐阅读
- powershell - 在 foreach UNIQUE 中创建“cmd /c”命令
- android - 如何在不更新 APK 文件的情况下解决违反使用 Android 广告 ID 政策和第 4.8 节的问题
- command-line-interface - Express Gateway 命令行界面“例如”
- oracle - oracle out ref cursor to a loop
- c++ - 即使使用正确的标题,系统(“暂停”)也无法正常工作
- php - 删除在 Woocommerce 单一产品页面中保留库存信息的“添加到购物车”按钮
- security - 如何启动非活动工作站锁定?
- javascript - 从 MYSQL 中正确检索和格式化数据
- c++ - 在不知道编译时数组大小的情况下,从函数内全局删除和重新实例化数组结构
- mysql - 无法从 MySQL 8.0.12 降级到早期版本