template and cloze changes

While writing the documentation I realized that the default templates were
somewhat overwhelming. So I've moved the default settings into the card css,
and moved the css into a separate attribute which gets combined with the
question and answer templates.

Also:
- Detect cloze references directly rather than the conditional wrapper
- Add the cloze css to the template
This commit is contained in:
Damien Elmes 2011-12-17 19:34:35 +09:00
parent 619a58216a
commit 9e35e4acf2
6 changed files with 37 additions and 44 deletions

View file

@ -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 "<style>%s</style>" % self.template()['css']
def _getQA(self, reload=False):
if not self._qa or reload:

View file

@ -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

View file

@ -6,32 +6,19 @@ from anki.lang import _
models = []
header = """\
<style>
.card {
text-align:center;
background-color:white;
}
</style>\n\n"""
def field(name, family="arial", size=20):
return """\
<span style="font-family:%s; font-size:%spx; color:black; \
white-space:pre-wrap;">{{%s}}</span>\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<hr id=answerStart>\n\n" + field(_("Back"))
t['qfmt'] = "{{Front}}"
t['afmt'] = t['qfmt'] + "\n\n<hr id=answer>\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'] + "<br>\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

View file

@ -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):

View file

@ -411,7 +411,7 @@ order by ordinal""", mid)):
# q fields now in a
if not hideq:
conf['afmt'] = (
conf['qfmt'] + "\n\n<hr id=answerStart>\n\n" + conf['afmt'])
conf['qfmt'] + "\n\n<hr id=answer>\n\n" + conf['afmt'])
tmpls.append(conf)
return tmpls

View file

@ -132,7 +132,7 @@ def test_cloze():
f = d.newNote()
f['Text'] = "hello {{c1::world::typical}}"
assert d.addNote(f) == 1
assert "<span class=cloze>[...(typical)]</span>" in f.cards()[0].q()
assert "<span class=cloze>[...typical]</span>" in f.cards()[0].q()
assert "<span class=cloze>world</span>" 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 "<span class=cloze>b</span> <span class=cloze>c</span>" 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()