兼容各操作系统平台的Anki选择题库模板

〇、在Anki中创建一个空的选择题模板:

兼容各操作系统平台的Anki选择题库模板_第1张图片

如上图, 通过工具菜单中的“管理笔记类型”命令打开笔记类型对话框,点击“添加”按钮添加一个“基础”类型类型的笔记,默认的名称类似于“基础-####”这样,点击重命名,将笔记类型的名称改为“选择题”或其他看着顺眼的名称,当然不改名也行。在“笔记类型”对话框左侧选择刚添加的笔记类型的名称,然后点击右边的“字段”按钮,即可添加所需的字段,添加完后可以将原来的字段删除;点击右边的“卡片”按钮,即可修改卡片模板的正面、背面和样式的模板。

一、字段设计

1、Question:选择题题干;

2、Options:选择题选项;

3、Answer:正确答案;

4、Extra:题目解析等附加信息。

二、目标

选择题计分规则为:单选正确得1分,错误得0分;多选如选择错误选项得0分,完全正确得2分,没有错误选项但是正确选项选择不完整(部分正确),所选的每个选项得0.5分。卡片正面显示题干和选项,选择选项后,点击显示答案进入背面,背面显示正确答案,累计得分,单多选题正确率等情况及解析信息。其中,正面显示的选项顺序随机排列,背面显示的选项顺序与正面要一致。正面和背面显示内容见以下图示。

正面:

兼容各操作系统平台的Anki选择题库模板_第2张图片

背面

兼容各操作系统平台的Anki选择题库模板_第3张图片

背面做错时:

兼容各操作系统平台的Anki选择题库模板_第4张图片

三、实现分析

有个Monokai风格的选择题模板在windows系统里基本实现了上述功能,但不能跨平台,另外我原来下载的那个版本js代码也写得稀乱的(特别是选项组合部分,居然用字符串拼接而不用DOM操作),不过只要解决跨平台问题以及重新改写下js代码就可以达到目的了。实现以上功能的关键在于将做练习时在正面所选择的选项以及正面显示的选项顺序传递到背面,此外还需要在整个一次练习中共享已做练习数量、已做练习正误情况及得分等信息。要在记忆卡正面和背面以及不同练习题之间共享信息,就需要将这些信息用js脚本持久化。而不同平台(windows、mac、android、ios、linux等)对js对象持久化的支持并不统一,anki本身在不同平台上的实现在对卡片的解析方式也不统一,Anki的android客户端没有持久化的窗口属性,而桌面客户端不允许使用sessionStorage属性,对于linux和mac 2.1客户端,还需要额外的考虑:window属性,在审查模式下是持久的,在预览模式下是存在的--但不是持久的。github上有一个项目anki-persistence,提供了兼容各种平台实现anki中js对象持久化的功能,作者为Simon Lammer。该脚本内容如下:

// v0.5.3 - https://github.com/SimonLammer/anki-persistence/blob/7107e73086189c190c4d326ef11ebbcded9a08c6/script.js
    if (void 0 === window.Persistence) {
        var _persistenceKey = "github.com/SimonLammer/anki-persistence/",
            _defaultKey = "_default";
        if (window.Persistence_sessionStorage = function() {
                var e = !1;
                try {
                    "object" == typeof window.sessionStorage && (e = !0, this.clear = function() {
                        for (var e = 0; e < sessionStorage.length; e++) {
                            var t = sessionStorage.key(e);
                            0 == t.indexOf(_persistenceKey) && (sessionStorage.removeItem(t), e--)
                        }
                    }, this.setItem = function(e, t) {
                        void 0 == t && (t = e, e = _defaultKey), sessionStorage.setItem(_persistenceKey + e, JSON.stringify(t))
                    }, this.getItem = function(e) {
                        return void 0 == e && (e = _defaultKey), JSON.parse(sessionStorage.getItem(_persistenceKey + e))
                    }, this.removeItem = function(e) {
                        void 0 == e && (e = _defaultKey), sessionStorage.removeItem(_persistenceKey + e)
                    })
                } catch (e) {}
                this.isAvailable = function() {
                    return e
                }
            }, window.Persistence_windowKey = function(e) {
                var t = window[e],
                    i = !1;
                "object" == typeof t && (i = !0, this.clear = function() {
                    t[_persistenceKey] = {}
                }, this.setItem = function(e, i) {
                    void 0 == i && (i = e, e = _defaultKey), t[_persistenceKey][e] = i
                }, this.getItem = function(e) {
                    return void 0 == e && (e = _defaultKey), void 0 == t[_persistenceKey][e] ? null : t[_persistenceKey][e]
                }, this.removeItem = function(e) {
                    void 0 == e && (e = _defaultKey), delete t[_persistenceKey][e]
                }, void 0 == t[_persistenceKey] && this.clear()), this.isAvailable = function() {
                    return i
                }
            }, window.Persistence = new Persistence_sessionStorage, Persistence.isAvailable() || (window.Persistence = new Persistence_windowKey("py")), !Persistence.isAvailable()) {
            var titleStartIndex = window.location.toString().indexOf("title"),
                titleContentIndex = window.location.toString().indexOf("main", titleStartIndex);
            titleStartIndex > 0 && titleContentIndex > 0 && titleContentIndex - titleStartIndex < 10 && (window.Persistence = new Persistence_windowKey("qt"))
        }
    }

此脚本有两个独立的持久性的内部实现:Persistence_sessionStorage和Persistence_windowKey。前者使用sessionStorage属性,而后者将一个新的属性附加到窗口对象现有的持久化(不会在anki记忆卡的正面和背面之间改变)属性上,并使用该附加属性来持久化和检索数据。使用方法是在正面模板和背面模板最开头用

{{edit:Question}}

    2、背面模板

    
    
     
    
    正确率:100%

    {{edit:Question}}

      上面的选项以此种形式显示的为被你选中的正确选项,以此种形式显示的为未被你选中的正确选项,以此种形式显示的不是正确选项却被你选中了。本题结果如下:

      【解析】
      {{edit:Extra}}

      3、样式

      .card { font-family: 微软雅黑; font-size:1.2em; text-align:left; 
      			color: white; background-color:#000;letter-spacing:2px;}
      	table{border-collapse:collapse; }
      	td{padding:5px;text-align:center;border:2px solid green;vertical-align: middle;}
      	td.left{text-align:left;}
      	td.red{
      		border-right: solid thick red;
      	}
      	hr{border: none;
      		height: 5px;
      		background-color:yellow;}
      	p{text-indent:2em;}
      	div{margin:5px auto }
      	.text{color:#ff0;font-weight:bold;font-size:1.2em;}
      .small_text{color:#ff0;font-weight:bold;font-size:0.9em;}
      	.imp,a,a:visited,a:hover,a:link,a:active{color:#F90;font:normal bold 微软雅黑,sans-serif;}
      	.hint{color:#a6e22e;}
      	.unchoiced{ color: white;}
      	.choiced{font-weight: bold; color: #0f3;background-color:#a0a;}
      	.extra{ margin-top:15px; font-size:1.2em; line-height:1.5em;color: #eeeebb; text-align:left;}
      	.green,i{  font-weight: bold; font-style:normal;color: #0f0;}
      	.blue,b{ font-weight: bold; font-style:normal;color: #3ff;}
      	.wrong{  font-weight: bold;  color: red;text-decoration:line-through;}
      	.options{ list-style:upper-latin;font-size:1.2em;}
      	.options *{ cursor:pointer;}
      	/*.options *:hover{ font-weight:bold;color: #f90;}*/
      	.options li{ margin-top:0.8em;}
      	/*下面两行样式定义决定是否显示选项前面的圆形或方形框,注释掉就会显示*/
      	.options input[type="radio"]{display:none;}
      	.options input[type="checkbox"]{display:none;}
      	#performance{ text-align:left; font-size:16px;}
      

      对css作了进一步修改:考虑到a、b、i标签比带class属性的span标签更容易输入,所以将这几个标签都加入了样式表。a标签等价于class属性为imp的span标签,b标签等价于class属性为blue的span标签,i标签等价于class属性为green的span标签。这样,在anki中修改文字样式时只需要选中文字后点击编辑界面上的B和I按钮就相当于输入了对应的span标签,利用Edit Field During Review插件修改卡片时,只需输入a、b、i标签,而无需输入这样一长串字符。

      上述模板中js代码逻辑比较简单,并且有不少注释,不再细述。代码有些是拷贝的以前的,所以风格不完全一致,也没有做模块化的函数包装,各位可以自行优化。css样式最小的需要只有代码里出现过的类名需要定义,上面的样式可以简化以及重新编写,仅供参考。此前在csdn中看到一篇帖子问pc可以正常运行的选择题模板为什么在手机上不能正确运行,当时我回了个帖子说有空了直接贴代码,希望那一位真的能看到这个代码。顺便说下,我用这个模板做了全套一建二建的题库,使用效果良好。

      你可能感兴趣的:(anki,编辑器,javascript)