commit
6da0e688b3
@ -510,13 +510,11 @@ where c.nid = n.id and c.id in %s group by nid""" % ids2str(cids)):
|
|||||||
afmt = afmt or template['afmt']
|
afmt = afmt or template['afmt']
|
||||||
for (type, format) in (("q", qfmt), ("a", afmt)):
|
for (type, format) in (("q", qfmt), ("a", afmt)):
|
||||||
if type == "q":
|
if type == "q":
|
||||||
format = format.replace("{{cloze:", "{{cq:%d:" % (
|
format = re.sub("{{(.*?)cloze:", r"{{\1cq-%d:" % (data[4]+1), format)
|
||||||
data[4]+1))
|
|
||||||
format = format.replace("<%cloze:", "<%%cq:%d:" % (
|
format = format.replace("<%cloze:", "<%%cq:%d:" % (
|
||||||
data[4]+1))
|
data[4]+1))
|
||||||
else:
|
else:
|
||||||
format = format.replace("{{cloze:", "{{ca:%d:" % (
|
format = re.sub("{{(.*?)cloze:", r"{{\1ca-%d:" % (data[4]+1), format)
|
||||||
data[4]+1))
|
|
||||||
format = format.replace("<%cloze:", "<%%ca:%d:" % (
|
format = format.replace("<%cloze:", "<%%ca:%d:" % (
|
||||||
data[4]+1))
|
data[4]+1))
|
||||||
fields['FrontSide'] = stripSounds(d['q'])
|
fields['FrontSide'] = stripSounds(d['q'])
|
||||||
|
@ -569,7 +569,7 @@ select id from notes where mid = ?)""" % " ".join(map),
|
|||||||
sflds = splitFields(flds)
|
sflds = splitFields(flds)
|
||||||
map = self.fieldMap(m)
|
map = self.fieldMap(m)
|
||||||
ords = set()
|
ords = set()
|
||||||
matches = re.findall("{{cloze:(.+?)}}", m['tmpls'][0]['qfmt'])
|
matches = re.findall("{{[^}]*?cloze:(?:.*?:)*(.+?)}}", m['tmpls'][0]['qfmt'])
|
||||||
matches += re.findall("<%cloze:(.+?)%>", m['tmpls'][0]['qfmt'])
|
matches += re.findall("<%cloze:(.+?)%>", m['tmpls'][0]['qfmt'])
|
||||||
for fname in matches:
|
for fname in matches:
|
||||||
if fname not in map:
|
if fname not in map:
|
||||||
|
@ -158,40 +158,42 @@ class Template(object):
|
|||||||
return txt
|
return txt
|
||||||
|
|
||||||
# field modifiers
|
# field modifiers
|
||||||
parts = tag_name.split(':',2)
|
parts = tag_name.split(':')
|
||||||
extra = None
|
extra = None
|
||||||
if len(parts) == 1 or parts[0] == '':
|
if len(parts) == 1 or parts[0] == '':
|
||||||
return '{unknown field %s}' % tag_name
|
return '{unknown field %s}' % tag_name
|
||||||
elif len(parts) == 2:
|
else:
|
||||||
(mod, tag) = parts
|
mods, tag = parts[:-1], parts[-1] #py3k has *mods, tag = parts
|
||||||
elif len(parts) == 3:
|
|
||||||
(mod, extra, tag) = parts
|
|
||||||
|
|
||||||
txt = get_or_attr(context, tag)
|
txt = get_or_attr(context, tag)
|
||||||
|
|
||||||
# built-in modifiers
|
#Since 'text:' and other mods can affect html on which Anki relies to
|
||||||
if mod == 'text':
|
#process Clozes and Types, we need to make sure cloze/type are always
|
||||||
# strip html
|
#treated after all the other mods, regardless of how they're specified
|
||||||
if txt:
|
#in the template, so that {{cloze:text: == {{text:cloze:
|
||||||
return stripHTML(txt)
|
mods.reverse()
|
||||||
return ""
|
mods.sort(key=lambda s: s.startswith("cq-") or s.startswith("ca-") or s=="type")
|
||||||
elif mod == 'type':
|
|
||||||
# type answer field; convert it to [[type:...]] for the gui code
|
for mod in mods:
|
||||||
# to process
|
# built-in modifiers
|
||||||
return "[[%s]]" % tag_name
|
if mod == 'text':
|
||||||
elif mod == 'cq' or mod == 'ca':
|
# strip html
|
||||||
# cloze deletion
|
txt = stripHTML(txt) if txt else ""
|
||||||
if txt and extra:
|
elif mod == 'type':
|
||||||
return self.clozeText(txt, extra, mod[1])
|
# type answer field; convert it to [[type:...]] for the gui code
|
||||||
|
# to process
|
||||||
|
txt = "[[%s]]" % tag_name
|
||||||
|
elif mod.startswith('cq-') or mod.startswith('ca-'):
|
||||||
|
# cloze deletion
|
||||||
|
mod, extra = mod.split("-")
|
||||||
|
txt = self.clozeText(txt, extra, mod[1]) if txt and extra else ""
|
||||||
else:
|
else:
|
||||||
return ""
|
# hook-based field modifier
|
||||||
else:
|
txt = runFilter('fmod_' + mod, txt or '', extra, context,
|
||||||
# hook-based field modifier
|
tag, tag_name);
|
||||||
txt = runFilter('fmod_' + mod, txt or '', extra, context,
|
if txt is None:
|
||||||
tag, tag_name);
|
return '{unknown field %s}' % tag_name
|
||||||
if txt is None:
|
return txt
|
||||||
return '{unknown field %s}' % tag_name
|
|
||||||
return txt
|
|
||||||
|
|
||||||
def clozeText(self, txt, ord, type):
|
def clozeText(self, txt, ord, type):
|
||||||
reg = clozeReg
|
reg = clozeReg
|
||||||
|
@ -107,6 +107,29 @@ def test_templates():
|
|||||||
mm.addTemplate(m, t)
|
mm.addTemplate(m, t)
|
||||||
assert not d.models.remTemplate(m, m['tmpls'][0])
|
assert not d.models.remTemplate(m, m['tmpls'][0])
|
||||||
|
|
||||||
|
def test_cloze_ordinals():
|
||||||
|
d = getEmptyDeck()
|
||||||
|
d.models.setCurrent(d.models.byName("Cloze"))
|
||||||
|
m = d.models.current(); mm = d.models
|
||||||
|
|
||||||
|
#We replace the default Cloze template
|
||||||
|
t = mm.newTemplate("ChainedCloze")
|
||||||
|
t['qfmt'] = "{{cloze:text:Text}}"
|
||||||
|
t['afmt'] = "{{text:cloze:Text}}" #independent of the order of mods
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
|
d.models.remTemplate(m, m['tmpls'][0])
|
||||||
|
|
||||||
|
f = d.newNote()
|
||||||
|
f['Text'] = u'{{c1::firstQ::firstA}}{{c2::secondQ::secondA}}'
|
||||||
|
d.addNote(f)
|
||||||
|
assert d.cardCount() == 2
|
||||||
|
(c, c2) = f.cards()
|
||||||
|
# first card should have first ord
|
||||||
|
assert c.ord == 0
|
||||||
|
assert c2.ord == 1
|
||||||
|
|
||||||
|
|
||||||
def test_text():
|
def test_text():
|
||||||
d = getEmptyDeck()
|
d = getEmptyDeck()
|
||||||
m = d.models.current()
|
m = d.models.current()
|
||||||
@ -163,6 +186,29 @@ def test_cloze():
|
|||||||
f.flush()
|
f.flush()
|
||||||
assert len(f.cards()) == 2
|
assert len(f.cards()) == 2
|
||||||
|
|
||||||
|
def test_chained_mods():
|
||||||
|
d = getEmptyDeck()
|
||||||
|
d.models.setCurrent(d.models.byName("Cloze"))
|
||||||
|
m = d.models.current(); mm = d.models
|
||||||
|
|
||||||
|
#We replace the default Cloze template
|
||||||
|
t = mm.newTemplate("ChainedCloze")
|
||||||
|
t['qfmt'] = "{{cloze:text:Text}}"
|
||||||
|
t['afmt'] = "{{text:cloze:Text}}" #independent of the order of mods
|
||||||
|
mm.addTemplate(m, t)
|
||||||
|
mm.save(m)
|
||||||
|
d.models.remTemplate(m, m['tmpls'][0])
|
||||||
|
|
||||||
|
f = d.newNote()
|
||||||
|
q1 = '<span style=\"color:red\">phrase</span>'
|
||||||
|
a1 = '<b>sentence</b>'
|
||||||
|
q2 = '<span style=\"color:red\">en chaine</span>'
|
||||||
|
a2 = '<i>chained</i>'
|
||||||
|
f['Text'] = "This {{c1::%s::%s}} demonstrates {{c1::%s::%s}} clozes." % (q1,a1,q2,a2)
|
||||||
|
assert d.addNote(f) == 1
|
||||||
|
assert "This <span class=cloze>[sentence]</span> demonstrates <span class=cloze>[chained]</span> clozes." in f.cards()[0].q()
|
||||||
|
assert "This <span class=cloze>phrase</span> demonstrates <span class=cloze>en chaine</span> clozes." in f.cards()[0].a()
|
||||||
|
|
||||||
def test_modelChange():
|
def test_modelChange():
|
||||||
deck = getEmptyDeck()
|
deck = getEmptyDeck()
|
||||||
basic = deck.models.byName("Basic")
|
basic = deck.models.byName("Basic")
|
||||||
|
Loading…
Reference in New Issue
Block a user