mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 15:02:21 -04:00
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:
parent
619a58216a
commit
9e35e4acf2
6 changed files with 37 additions and 44 deletions
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue