diff --git a/anki/cards.py b/anki/cards.py index d796a9eae..6b4b5eb85 100644 --- a/anki/cards.py +++ b/anki/cards.py @@ -101,10 +101,13 @@ lapses=?, left=?, edue=? where id = ?""", self.left, self.edue, self.id) def q(self, reload=False): - return self._getQA(reload)['q'] + return self.css() + self._getQA(reload)['q'] def a(self): - return self._getQA()['a'] + return self.css() + self._getQA()['a'] + + def css(self): + return "" % self.template()['css'] def _getQA(self, reload=False): if not self._qa or reload: diff --git a/anki/models.py b/anki/models.py index 07ffe571f..4e4031f39 100644 --- a/anki/models.py +++ b/anki/models.py @@ -49,6 +49,15 @@ defaultTemplate = { 'qfmt': "", 'afmt': "", 'did': None, + 'css': """\ +.card { + font-family: arial; + font-size: 20px; + text-align: center; + color: black; + background-color: white; +} +""" } class ModelManager(object): @@ -432,7 +441,7 @@ select id from notes where mid = ?)""" % " ".join(map), if cloze: # need a cloze-specific filler cloze = "" - nums = re.findall("\{\{#cloze:(\d+):", t['qfmt']) + nums = re.findall("\{\{cloze:(\d+):", t['qfmt']) for n in nums: n = int(n) cloze += "{{c%d::foo}}" % n diff --git a/anki/stdmodels.py b/anki/stdmodels.py index 32954865f..f0ad3578b 100644 --- a/anki/stdmodels.py +++ b/anki/stdmodels.py @@ -6,32 +6,19 @@ from anki.lang import _ models = [] -header = """\ -\n\n""" - -def field(name, family="arial", size=20): - return """\ -{{%s}}\n""" % (family, size, name) - # Basic ########################################################################## def addBasicModel(col): mm = col.models - m = mm.new(_("Basic")) #2 field note")) + m = mm.new(_("Basic")) fm = mm.newField(_("Front")) mm.addField(m, fm) fm = mm.newField(_("Back")) mm.addField(m, fm) t = mm.newTemplate(_("Forward")) - t['qfmt'] = header + field(_("Front")) - t['afmt'] = t['qfmt'] + "\n\n
\n\n" + field(_("Back")) + t['qfmt'] = "{{Front}}" + t['afmt'] = t['qfmt'] + "\n\n
\n\n{{Back}}" mm.addTemplate(m, t) mm.add(m) return m @@ -51,10 +38,14 @@ def addClozeModel(col): for i in range(8): n = i+1 t = mm.newTemplate(_("Cloze") + " %d" % n) - t['qfmt'] = header + ("{{#cloze:%d:Text}}\n"+ - field("cloze:%d:Text" % n)+ - "{{/cloze:%d:Text}}") % (n, n) - t['afmt'] = t['qfmt'] + "
\n"+field("Notes") + fmt = "{{cloze:%d:Text}}%%s" % n + t['css'] += """ +.cloze { + font-weight: bold; + color: blue; +}""" + t['qfmt'] = fmt % "" + t['afmt'] = fmt % "\n{{Notes}}" mm.addTemplate(m, t) mm.add(m) return m diff --git a/anki/template/template.py b/anki/template/template.py index c4640f4a7..7135d99a6 100644 --- a/anki/template/template.py +++ b/anki/template/template.py @@ -138,10 +138,7 @@ class Template(object): # {{{ functions just like {{ in anki @modifier('{') def render_tag(self, tag_name, context): - raw = get_or_attr(context, tag_name, '') - if not raw and raw is not 0: - return '' - return raw + return render_unescaped(tag_name, context) @modifier('!') def render_comment(self, tag_name=None, context=None): @@ -152,6 +149,7 @@ class Template(object): def render_unescaped(self, tag_name=None, context=None): """Render a tag without escaping it.""" if tag_name.startswith("text:"): + # strip html tag = tag_name[5:] txt = get_or_attr(context, tag) if txt: @@ -163,12 +161,14 @@ class Template(object): return "[[%s]]" % tag_name elif (tag_name.startswith("cq:") or tag_name.startswith("ca:")): + # cloze deletion m = re.match("c(.+):(\d+):(.+)", tag_name) (type, ord, tag) = (m.group(1), m.group(2), m.group(3)) txt = get_or_attr(context, tag) if txt: return self.clozeText(txt, ord, type) return "" + # regular field return get_or_attr(context, tag_name, '{unknown field %s}' % tag_name) def clozeText(self, txt, ord, type): diff --git a/anki/upgrade.py b/anki/upgrade.py index e3475edc2..64fe4c98a 100644 --- a/anki/upgrade.py +++ b/anki/upgrade.py @@ -411,7 +411,7 @@ order by ordinal""", mid)): # q fields now in a if not hideq: conf['afmt'] = ( - conf['qfmt'] + "\n\n
\n\n" + conf['afmt']) + conf['qfmt'] + "\n\n
\n\n" + conf['afmt']) tmpls.append(conf) return tmpls diff --git a/tests/test_models.py b/tests/test_models.py index 56fe7ccc7..8e743e8f1 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -132,7 +132,7 @@ def test_cloze(): f = d.newNote() f['Text'] = "hello {{c1::world::typical}}" assert d.addNote(f) == 1 - assert "[...(typical)]" in f.cards()[0].q() + assert "[...typical]" in f.cards()[0].q() assert "world" in f.cards()[0].a() # and with 2 clozes f = d.newNote() @@ -150,16 +150,6 @@ def test_cloze(): assert d.addNote(f) == 1 assert "b c" in ( f.cards()[0].a()) - # clozes should be supported in sections too - m = d.models.current() - m['tmpls'][0]['qfmt'] = "{{#cloze:1:Text}}{{Notes}}{{/cloze:1:Text}}" - d.models.save(m) - f = d.newNote() - f['Text'] = "hello" - f['Notes'] = "world" - assert d.addNote(f) == 0 - f['Text'] = "hello {{c1::foo}}" - assert d.addNote(f) == 1 # if we add another cloze, a card should be generated cnt = d.cardCount() f['Text'] = "{{c2::hello}} {{c1::foo}}" @@ -179,25 +169,25 @@ def test_modelChange(): mm.save(m) f = deck.newNote() f['Front'] = u'f' - f['Back'] = u'b' + f['Back'] = u'b123' deck.addNote(f) # switch fields map = {0: 1, 1: 0} deck.models.change(basic, [f.id], basic, map, None) f.load() - assert f['Front'] == 'b' + assert f['Front'] == 'b123' assert f['Back'] == 'f' # switch cards c0 = f.cards()[0] c1 = f.cards()[1] - assert ">b<" in c0.q() + assert "b123" in c0.q() assert "f" in c1.q() assert c0.ord == 0 assert c1.ord == 1 deck.models.change(basic, [f.id], basic, None, map) f.load(); c0.load(); c1.load() assert "f" in c0.q() - assert ">b<" in c1.q() + assert "b123" in c1.q() assert c0.ord == 1 assert c1.ord == 0 # .cards() returns cards in order @@ -214,7 +204,7 @@ def test_modelChange(): pass assert len(f.cards()) == 1 # an unmapped field becomes blank - assert f['Front'] == 'b' + assert f['Front'] == 'b123' assert f['Back'] == 'f' deck.models.change(basic, [f.id], basic, map, None) f.load()