mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
convert templates to a json object, and replace tid with ord
it's faster for us to parse another json string than pull a record from a separate db table, and this makes templates and fields consistent
This commit is contained in:
parent
9cec4b2059
commit
93dcfceffe
9 changed files with 112 additions and 193 deletions
|
@ -28,7 +28,7 @@ class Card(object):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.load()
|
self.load()
|
||||||
else:
|
else:
|
||||||
# to flush, set fid, tid, and due
|
# to flush, set fid, ord, and due
|
||||||
self.id = None
|
self.id = None
|
||||||
self.gid = 1
|
self.gid = 1
|
||||||
self.crt = intTime()
|
self.crt = intTime()
|
||||||
|
@ -46,8 +46,8 @@ class Card(object):
|
||||||
def load(self):
|
def load(self):
|
||||||
(self.id,
|
(self.id,
|
||||||
self.fid,
|
self.fid,
|
||||||
self.tid,
|
|
||||||
self.gid,
|
self.gid,
|
||||||
|
self.ord,
|
||||||
self.crt,
|
self.crt,
|
||||||
self.mod,
|
self.mod,
|
||||||
self.type,
|
self.type,
|
||||||
|
@ -71,8 +71,8 @@ insert or replace into cards values
|
||||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
|
||||||
self.id,
|
self.id,
|
||||||
self.fid,
|
self.fid,
|
||||||
self.tid,
|
|
||||||
self.gid,
|
self.gid,
|
||||||
|
self.ord,
|
||||||
self.crt,
|
self.crt,
|
||||||
self.mod,
|
self.mod,
|
||||||
self.type,
|
self.type,
|
||||||
|
|
45
anki/deck.py
45
anki/deck.py
|
@ -401,9 +401,8 @@ due > :now and due < :now""", now=time.time())
|
||||||
for template in cms:
|
for template in cms:
|
||||||
card = anki.cards.Card(self)
|
card = anki.cards.Card(self)
|
||||||
card.fid = fact.id
|
card.fid = fact.id
|
||||||
card.tid = template.id
|
card.ord = template['ord']
|
||||||
card.ord = template.ord
|
card.gid = template['gid'] or gid
|
||||||
card.gid = template.conf['gid'] or gid
|
|
||||||
if isRandom:
|
if isRandom:
|
||||||
card.due = due
|
card.due = due
|
||||||
else:
|
else:
|
||||||
|
@ -418,19 +417,21 @@ due > :now and due < :now""", now=time.time())
|
||||||
def findTemplates(self, fact, checkActive=True):
|
def findTemplates(self, fact, checkActive=True):
|
||||||
"Return active, non-empty templates."
|
"Return active, non-empty templates."
|
||||||
ok = []
|
ok = []
|
||||||
for template in fact.model.templates:
|
for c, template in enumerate(fact.model.templates):
|
||||||
if template.active or not checkActive:
|
if template['actv'] or not checkActive:
|
||||||
# [cid, fid, mid, tid, gid, tags, flds, data]
|
# [cid, fid, mid, gid, ord, tags, flds, data]
|
||||||
data = [1, 1, fact.model.id, template.id, 1,
|
data = [1, 1, fact.model.id, 1, c,
|
||||||
"", fact.joinedFields(), ""]
|
"", fact.joinedFields(), ""]
|
||||||
now = self._renderQA(fact.model, template, "", data)
|
now = self._renderQA(fact.model, "", data)
|
||||||
data[6] = "\x1f".join([""]*len(fact._fields))
|
data[6] = "\x1f".join([""]*len(fact._fields))
|
||||||
empty = self._renderQA(fact.model, template, "", data)
|
empty = self._renderQA(fact.model, "", data)
|
||||||
if now['q'] == empty['q']:
|
if now['q'] == empty['q']:
|
||||||
continue
|
continue
|
||||||
if not template.conf['allowEmptyAns']:
|
if not template['emptyAns']:
|
||||||
if now['a'] == empty['a']:
|
if now['a'] == empty['a']:
|
||||||
continue
|
continue
|
||||||
|
# add ordinal
|
||||||
|
template['ord'] = c
|
||||||
ok.append(template)
|
ok.append(template)
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
|
@ -647,7 +648,6 @@ select id from cards where fid in (select id from facts where mid = ?)""",
|
||||||
mid))
|
mid))
|
||||||
# then the model
|
# then the model
|
||||||
self.db.execute("delete from models where id = ?", mid)
|
self.db.execute("delete from models where id = ?", mid)
|
||||||
self.db.execute("delete from templates where mid = ?", mid)
|
|
||||||
# GUI should ensure last model is not deleted
|
# GUI should ensure last model is not deleted
|
||||||
if self.conf['currentModelId'] == mid:
|
if self.conf['currentModelId'] == mid:
|
||||||
self.conf['currentModelId'] = self.db.scalar(
|
self.conf['currentModelId'] = self.db.scalar(
|
||||||
|
@ -861,18 +861,15 @@ where tid in %s""" % strids, now=time.time())
|
||||||
else:
|
else:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
mods = {}
|
mods = {}
|
||||||
templs = {}
|
|
||||||
for m in self.allModels():
|
for m in self.allModels():
|
||||||
mods[m.id] = m
|
mods[m.id] = m
|
||||||
for t in m.templates:
|
|
||||||
templs[t.id] = t
|
|
||||||
groups = dict(self.db.all("select id, name from groups"))
|
groups = dict(self.db.all("select id, name from groups"))
|
||||||
return [self._renderQA(mods[row[2]], templs[row[3]], groups[row[4]], row)
|
return [self._renderQA(mods[row[2]], groups[row[3]], row)
|
||||||
for row in self._qaData(where)]
|
for row in self._qaData(where)]
|
||||||
|
|
||||||
def _renderQA(self, model, template, gname, data, filters=True):
|
def _renderQA(self, model, gname, data, filters=True):
|
||||||
"Returns hash of id, question, answer."
|
"Returns hash of id, question, answer."
|
||||||
# data is [cid, fid, mid, tid, gid, tags, flds, data]
|
# data is [cid, fid, mid, gid, ord, tags, flds, data]
|
||||||
# unpack fields and create dict
|
# unpack fields and create dict
|
||||||
flist = data[6].split("\x1f")
|
flist = data[6].split("\x1f")
|
||||||
fields = {}
|
fields = {}
|
||||||
|
@ -888,11 +885,12 @@ where tid in %s""" % strids, now=time.time())
|
||||||
fields[name] = ""
|
fields[name] = ""
|
||||||
fields['Tags'] = data[5]
|
fields['Tags'] = data[5]
|
||||||
fields['Model'] = model.name
|
fields['Model'] = model.name
|
||||||
fields['Template'] = template.name
|
|
||||||
fields['Group'] = gname
|
fields['Group'] = gname
|
||||||
|
template = model.templates[data[4]]
|
||||||
|
fields['Template'] = template['name']
|
||||||
# render q & a
|
# render q & a
|
||||||
d = dict(id=data[0])
|
d = dict(id=data[0])
|
||||||
for (type, format) in (("q", template.qfmt), ("a", template.afmt)):
|
for (type, format) in (("q", template['qfmt']), ("a", template['afmt'])):
|
||||||
# if filters:
|
# if filters:
|
||||||
# fields = runFilter("renderQA.pre", fields, , self)
|
# fields = runFilter("renderQA.pre", fields, , self)
|
||||||
html = anki.template.render(format, fields)
|
html = anki.template.render(format, fields)
|
||||||
|
@ -903,12 +901,11 @@ where tid in %s""" % strids, now=time.time())
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def _qaData(self, where=""):
|
def _qaData(self, where=""):
|
||||||
"Return [cid, fid, mid, tid, gid, tags, flds, data] db query"
|
"Return [cid, fid, mid, gid, ord, tags, flds, data] db query"
|
||||||
return self.db.execute("""
|
return self.db.execute("""
|
||||||
select c.id, f.id, m.id, t.id, g.id, f.tags, f.flds, f.data
|
select c.id, f.id, m.id, g.id, c.ord, f.tags, f.flds, f.data
|
||||||
from cards c, facts f, models m, templates t, groups g
|
from cards c, facts f, models m, groups g
|
||||||
where c.fid == f.id and f.mid == m.id and
|
where c.fid == f.id and f.mid == m.id and c.gid = g.id
|
||||||
c.tid = t.id and c.gid = g.id
|
|
||||||
%s""" % where)
|
%s""" % where)
|
||||||
|
|
||||||
# Field checksum bulk update
|
# Field checksum bulk update
|
||||||
|
|
129
anki/models.py
129
anki/models.py
|
@ -12,6 +12,31 @@ from anki.lang import _
|
||||||
defaultConf = {
|
defaultConf = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultField = {
|
||||||
|
'name': "",
|
||||||
|
'rtl': False,
|
||||||
|
'req': False,
|
||||||
|
'uniq': False,
|
||||||
|
'font': "Arial",
|
||||||
|
'qsize': 20,
|
||||||
|
'esize': 20,
|
||||||
|
'qcol': "#fff",
|
||||||
|
'pre': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTemplate = {
|
||||||
|
'name': "",
|
||||||
|
'actv': True,
|
||||||
|
'qfmt': "",
|
||||||
|
'afmt': "",
|
||||||
|
'hideQ': False,
|
||||||
|
'align': 0,
|
||||||
|
'bg': "#000",
|
||||||
|
'emptyAns': None,
|
||||||
|
'typeAns': None,
|
||||||
|
'gid': None
|
||||||
|
}
|
||||||
|
|
||||||
class Model(object):
|
class Model(object):
|
||||||
|
|
||||||
def __init__(self, deck, id=None):
|
def __init__(self, deck, id=None):
|
||||||
|
@ -32,34 +57,29 @@ class Model(object):
|
||||||
(self.mod,
|
(self.mod,
|
||||||
self.name,
|
self.name,
|
||||||
self.fields,
|
self.fields,
|
||||||
|
self.templates,
|
||||||
self.conf) = self.deck.db.first("""
|
self.conf) = self.deck.db.first("""
|
||||||
select mod, name, flds, conf from models where id = ?""", self.id)
|
select mod, name, flds, tmpls, conf from models where id = ?""", self.id)
|
||||||
self.fields = simplejson.loads(self.fields)
|
self.fields = simplejson.loads(self.fields)
|
||||||
|
self.templates = simplejson.loads(self.templates)
|
||||||
self.conf = simplejson.loads(self.conf)
|
self.conf = simplejson.loads(self.conf)
|
||||||
self.loadTemplates()
|
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
self.mod = intTime()
|
self.mod = intTime()
|
||||||
ret = self.deck.db.execute("""
|
ret = self.deck.db.execute("""
|
||||||
insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
insert or replace into models values (?, ?, ?, ?, ?, ?, ?)""",
|
||||||
self.id, self.mod, self.name,
|
self.id, self.mod, self.name,
|
||||||
simplejson.dumps(self.fields),
|
simplejson.dumps(self.fields),
|
||||||
|
simplejson.dumps(self.templates),
|
||||||
simplejson.dumps(self.conf),
|
simplejson.dumps(self.conf),
|
||||||
self.genCSS())
|
self.genCSS())
|
||||||
self.id = ret.lastrowid
|
self.id = ret.lastrowid
|
||||||
[t._flush() for t in self.templates]
|
|
||||||
|
|
||||||
def _getID(self):
|
|
||||||
if not self.id:
|
|
||||||
# flush so we can get our DB id
|
|
||||||
self.flush()
|
|
||||||
return self.id
|
|
||||||
|
|
||||||
# Fields
|
# Fields
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def newField(self):
|
def newField(self):
|
||||||
return defaultFieldConf.copy()
|
return defaultField.copy()
|
||||||
|
|
||||||
def addField(self, field):
|
def addField(self, field):
|
||||||
self.deck.modSchema()
|
self.deck.modSchema()
|
||||||
|
@ -70,20 +90,17 @@ insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
||||||
return dict([(f['name'], (c, f)) for c, f in enumerate(self.fields)])
|
return dict([(f['name'], (c, f)) for c, f in enumerate(self.fields)])
|
||||||
|
|
||||||
def sortField(self):
|
def sortField(self):
|
||||||
|
print "sortField() fixme"
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Templates
|
# Templates
|
||||||
##################################################
|
##################################################
|
||||||
|
|
||||||
def loadTemplates(self):
|
def newTemplate(self):
|
||||||
sql = "select * from templates where mid = ? order by ord"
|
return defaultTemplate.copy()
|
||||||
self.templates = [Template(self.deck, data)
|
|
||||||
for data in self.deck.db.all(sql, self.id)]
|
|
||||||
|
|
||||||
def addTemplate(self, template):
|
def addTemplate(self, template):
|
||||||
self.deck.modSchema()
|
self.deck.modSchema()
|
||||||
template.mid = self._getID()
|
|
||||||
template.ord = len(self.templates)
|
|
||||||
self.templates.append(template)
|
self.templates.append(template)
|
||||||
|
|
||||||
# Copying
|
# Copying
|
||||||
|
@ -95,15 +112,8 @@ insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
||||||
new.id = None
|
new.id = None
|
||||||
new.name += _(" copy")
|
new.name += _(" copy")
|
||||||
new.fields = [f.copy() for f in self.fields]
|
new.fields = [f.copy() for f in self.fields]
|
||||||
# get new id
|
new.templates = [t.copy() for t in self.templates]
|
||||||
t = new.templates; new.templates = []
|
|
||||||
new.flush()
|
new.flush()
|
||||||
# then put back
|
|
||||||
new.templates = t
|
|
||||||
for t in new.templates:
|
|
||||||
t.id = None
|
|
||||||
t.mid = new.id
|
|
||||||
t._flush()
|
|
||||||
return new
|
return new
|
||||||
|
|
||||||
# CSS generation
|
# CSS generation
|
||||||
|
@ -118,14 +128,10 @@ insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
||||||
(f['font'], f['qsize'], f['qcol'], f['rtl'], f['pre']))
|
(f['font'], f['qsize'], f['qcol'], f['rtl'], f['pre']))
|
||||||
for c, f in enumerate(self.fields)])
|
for c, f in enumerate(self.fields)])
|
||||||
# templates
|
# templates
|
||||||
for t in self.templates:
|
css += "".join(["#cm%s-%s {text-align:%s;background:%s}\n" % (
|
||||||
if not t.id:
|
hexifyID(self.id), hexifyID(c),
|
||||||
# not flushed yet, ignore for now
|
("center", "left", "right")[t['align']], t['bg'])
|
||||||
continue
|
for c, t in enumerate(self.templates)])
|
||||||
css += "#cm%s {text-align:%s;background:%s}\n" % (
|
|
||||||
hexifyID(t.id),
|
|
||||||
("center", "left", "right")[t.conf['align']],
|
|
||||||
t.conf['bg'])
|
|
||||||
return css
|
return css
|
||||||
|
|
||||||
def _rewriteFont(self, font):
|
def _rewriteFont(self, font):
|
||||||
|
@ -148,60 +154,3 @@ insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
||||||
t += "white-space:pre-wrap;"
|
t += "white-space:pre-wrap;"
|
||||||
t = "%s {%s}\n" % (prefix, t)
|
t = "%s {%s}\n" % (prefix, t)
|
||||||
return t
|
return t
|
||||||
|
|
||||||
# Field object
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
defaultFieldConf = {
|
|
||||||
'name': "",
|
|
||||||
'rtl': False,
|
|
||||||
'req': False,
|
|
||||||
'uniq': False,
|
|
||||||
'font': "Arial",
|
|
||||||
'qsize': 20,
|
|
||||||
'esize': 20,
|
|
||||||
'qcol': "#fff",
|
|
||||||
'pre': True,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Template object
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
defaultTemplateConf = {
|
|
||||||
'hideQ': False,
|
|
||||||
'align': 0,
|
|
||||||
'bg': "#000",
|
|
||||||
'allowEmptyAns': None,
|
|
||||||
'typeAnswer': None,
|
|
||||||
'gid': None
|
|
||||||
}
|
|
||||||
|
|
||||||
class Template(object):
|
|
||||||
|
|
||||||
def __init__(self, deck, data=None):
|
|
||||||
self.deck = deck
|
|
||||||
if data:
|
|
||||||
self.initFromData(data)
|
|
||||||
else:
|
|
||||||
self.id = None
|
|
||||||
self.active = True
|
|
||||||
self.conf = defaultTemplateConf.copy()
|
|
||||||
|
|
||||||
def initFromData(self, data):
|
|
||||||
(self.id,
|
|
||||||
self.mid,
|
|
||||||
self.ord,
|
|
||||||
self.name,
|
|
||||||
self.active,
|
|
||||||
self.qfmt,
|
|
||||||
self.afmt,
|
|
||||||
self.conf) = data
|
|
||||||
self.conf = simplejson.loads(self.conf)
|
|
||||||
|
|
||||||
def _flush(self):
|
|
||||||
ret = self.deck.db.execute("""
|
|
||||||
insert or replace into templates values (?, ?, ?, ?, ?, ?, ?, ?)""",
|
|
||||||
self.id, self.mid, self.ord, self.name,
|
|
||||||
self.active, self.qfmt, self.afmt,
|
|
||||||
simplejson.dumps(self.conf))
|
|
||||||
self.id = ret.lastrowid
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Copyright: Damien Elmes <anki@ichi2.net>
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
||||||
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
||||||
|
|
||||||
from anki.models import Model, Template
|
from anki.models import Model
|
||||||
from anki.lang import _
|
from anki.lang import _
|
||||||
|
|
||||||
models = []
|
models = []
|
||||||
|
@ -21,35 +21,17 @@ def BasicModel(deck):
|
||||||
fm = m.newField()
|
fm = m.newField()
|
||||||
fm['name'] = _("Back")
|
fm['name'] = _("Back")
|
||||||
m.addField(fm)
|
m.addField(fm)
|
||||||
t = Template(deck)
|
t = m.newTemplate()
|
||||||
t.name = _("Forward")
|
t['name'] = _("Forward")
|
||||||
t.qfmt = "{{" + _("Front") + "}}"
|
t['qfmt'] = "{{" + _("Front") + "}}"
|
||||||
t.afmt = "{{" + _("Back") + "}}"
|
t['afmt'] = "{{" + _("Back") + "}}"
|
||||||
m.addTemplate(t)
|
m.addTemplate(t)
|
||||||
t = Template(deck)
|
t = m.newTemplate()
|
||||||
t.name = _("Reverse")
|
t['name'] = _("Reverse")
|
||||||
t.qfmt = "{{" + _("Back") + "}}"
|
t['qfmt'] = "{{" + _("Back") + "}}"
|
||||||
t.afmt = "{{" + _("Front") + "}}"
|
t['afmt'] = "{{" + _("Front") + "}}"
|
||||||
t.active = False
|
t['actv'] = False
|
||||||
m.addTemplate(t)
|
m.addTemplate(t)
|
||||||
return m
|
return m
|
||||||
|
|
||||||
models.append(BasicModel)
|
models.append(BasicModel)
|
||||||
|
|
||||||
# Recovery
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
def RecoveryModel():
|
|
||||||
m.name = _("Recovery")
|
|
||||||
fm = Field(deck)
|
|
||||||
fm.name = _("Question")
|
|
||||||
m.addField(fm)
|
|
||||||
fm = Field(deck)
|
|
||||||
fm.name = _("Back")
|
|
||||||
m.addField(fm)
|
|
||||||
t = Template(deck)
|
|
||||||
t.name = _("Forward")
|
|
||||||
t.qfmt = "{{" + _("Question") + "}}"
|
|
||||||
t.afmt = "{{" + _("Back") + "}}"
|
|
||||||
m.addTemplate(t)
|
|
||||||
return m
|
|
||||||
|
|
|
@ -68,8 +68,8 @@ create table if not exists deck (
|
||||||
create table if not exists cards (
|
create table if not exists cards (
|
||||||
id integer primary key,
|
id integer primary key,
|
||||||
fid integer not null,
|
fid integer not null,
|
||||||
tid integer not null,
|
|
||||||
gid integer not null,
|
gid integer not null,
|
||||||
|
ord integer not null,
|
||||||
crt integer not null,
|
crt integer not null,
|
||||||
mod integer not null,
|
mod integer not null,
|
||||||
type integer not null,
|
type integer not null,
|
||||||
|
@ -107,21 +107,11 @@ create table if not exists models (
|
||||||
mod integer not null,
|
mod integer not null,
|
||||||
name text not null,
|
name text not null,
|
||||||
flds text not null,
|
flds text not null,
|
||||||
|
tmpls text not null,
|
||||||
conf text not null,
|
conf text not null,
|
||||||
css text not null
|
css text not null
|
||||||
);
|
);
|
||||||
|
|
||||||
create table if not exists templates (
|
|
||||||
id integer primary key,
|
|
||||||
mid integer not null,
|
|
||||||
ord integer not null,
|
|
||||||
name text not null,
|
|
||||||
actv integer not null,
|
|
||||||
qfmt text not null,
|
|
||||||
afmt text not null,
|
|
||||||
conf text not null
|
|
||||||
);
|
|
||||||
|
|
||||||
create table if not exists gconf (
|
create table if not exists gconf (
|
||||||
id integer primary key,
|
id integer primary key,
|
||||||
mod integer not null,
|
mod integer not null,
|
||||||
|
@ -320,7 +310,7 @@ originalPath from media2""")
|
||||||
_moveTable(db, "models")
|
_moveTable(db, "models")
|
||||||
db.execute("""
|
db.execute("""
|
||||||
insert into models select id, cast(modified as int),
|
insert into models select id, cast(modified as int),
|
||||||
name, "{}", "{}", "" from models2""")
|
name, "{}", "{}", "{}", "" from models2""")
|
||||||
db.execute("drop table models2")
|
db.execute("drop table models2")
|
||||||
|
|
||||||
# reviewHistory -> revlog
|
# reviewHistory -> revlog
|
||||||
|
@ -390,7 +380,7 @@ utcOffset, "", "", "" from decks""", t=intTime())
|
||||||
|
|
||||||
def _migrateFieldsTbl(db):
|
def _migrateFieldsTbl(db):
|
||||||
import anki.models
|
import anki.models
|
||||||
dconf = anki.models.defaultFieldConf
|
dconf = anki.models.defaultField
|
||||||
mods = {}
|
mods = {}
|
||||||
for row in db.all("""
|
for row in db.all("""
|
||||||
select id, modelId, ordinal, name, features, required, "unique",
|
select id, modelId, ordinal, name, features, required, "unique",
|
||||||
|
@ -420,47 +410,55 @@ quizFontFamily, quizFontSize, quizFontColour, editFontSize from fieldModels"""):
|
||||||
db.execute("drop table fieldModels")
|
db.execute("drop table fieldModels")
|
||||||
return mods
|
return mods
|
||||||
|
|
||||||
def _migrateTemplatesTbl(db, mods):
|
def _migrateTemplatesTbl(db, fmods):
|
||||||
import anki.models
|
import anki.models
|
||||||
db.execute("""
|
dconf = anki.models.defaultTemplate
|
||||||
insert into templates select id, modelId, ordinal, name, active, qformat,
|
mods = {}
|
||||||
aformat, '' from cardModels""")
|
|
||||||
dconf = anki.models.defaultTemplateConf
|
|
||||||
for row in db.all("""
|
for row in db.all("""
|
||||||
select id, modelId, questionInAnswer, questionAlign, lastFontColour,
|
select modelId, ordinal, name, active, qformat, aformat, questionInAnswer,
|
||||||
allowEmptyAnswer, typeAnswer from cardModels"""):
|
questionAlign, lastFontColour, allowEmptyAnswer, typeAnswer from cardModels"""):
|
||||||
conf = dconf.copy()
|
conf = dconf.copy()
|
||||||
(conf['hideQ'],
|
if row[1] not in mods:
|
||||||
|
mods[row[0]] = []
|
||||||
|
(conf['name'],
|
||||||
|
conf['actv'],
|
||||||
|
conf['qfmt'],
|
||||||
|
conf['afmt'],
|
||||||
|
conf['hideQ'],
|
||||||
conf['align'],
|
conf['align'],
|
||||||
conf['bg'],
|
conf['bg'],
|
||||||
conf['allowEmptyAns'],
|
conf['emptyAns'],
|
||||||
fname) = row[2:]
|
conf['typeAns']) = row[2:]
|
||||||
# convert the field name to an ordinal
|
# convert the field name to an ordinal
|
||||||
for (ord, fm) in mods[row[1]]:
|
ordN = None
|
||||||
|
for (ord, fm) in fmods[row[0]]:
|
||||||
if fm['name'] == row[1]:
|
if fm['name'] == row[1]:
|
||||||
conf['typeAnswer'] = ord
|
ordN = ord
|
||||||
break
|
break
|
||||||
# save
|
if ordN is not None:
|
||||||
db.execute("update templates set conf = ? where id = ?",
|
conf['typeAns'] = ordN
|
||||||
simplejson.dumps(conf), row[0])
|
else:
|
||||||
|
conf['typeAns'] = None
|
||||||
|
# ensure the new style field format
|
||||||
|
conf['qfmt'] = re.sub("%\((.+?)\)s", "{{\\1}}", conf['qfmt'])
|
||||||
|
conf['afmt'] = re.sub("%\((.+?)\)s", "{{\\1}}", conf['afmt'])
|
||||||
|
# add to model list with ordinal for sorting
|
||||||
|
mods[row[0]].append((row[1], conf))
|
||||||
|
# now we've gathered all the info, save it into the models
|
||||||
|
for mid, tmpls in mods.items():
|
||||||
|
db.execute("update models set tmpls = ? where id = ?",
|
||||||
|
simplejson.dumps([x[1] for x in sorted(tmpls)]), mid)
|
||||||
# clean up
|
# clean up
|
||||||
db.execute("drop table cardModels")
|
db.execute("drop table cardModels")
|
||||||
|
return mods
|
||||||
|
|
||||||
def _rewriteModelIds(deck):
|
def _rewriteModelIds(deck):
|
||||||
# rewrite model/template/field ids
|
# rewrite model/template/field ids
|
||||||
models = deck.allModels()
|
models = deck.allModels()
|
||||||
deck.db.execute("delete from models")
|
deck.db.execute("delete from models")
|
||||||
deck.db.execute("delete from templates")
|
|
||||||
for c, m in enumerate(models):
|
for c, m in enumerate(models):
|
||||||
old = m.id
|
old = m.id
|
||||||
m.id = c+1
|
m.id = c+1
|
||||||
for t in m.templates:
|
|
||||||
t.mid = m.id
|
|
||||||
oldT = t.id
|
|
||||||
t.id = None
|
|
||||||
t._flush()
|
|
||||||
deck.db.execute(
|
|
||||||
"update cards set tid = ? where tid = ?", t.mid, oldT)
|
|
||||||
m.flush()
|
m.flush()
|
||||||
deck.db.execute("update facts set mid = ? where mid = ?", m.id, old)
|
deck.db.execute("update facts set mid = ? where mid = ?", m.id, old)
|
||||||
|
|
||||||
|
@ -476,12 +474,6 @@ def _postSchemaUpgrade(deck):
|
||||||
"revCardsDue", "revCardsRandom", "acqCardsRandom",
|
"revCardsDue", "revCardsRandom", "acqCardsRandom",
|
||||||
"acqCardsOld", "acqCardsNew"):
|
"acqCardsOld", "acqCardsNew"):
|
||||||
deck.db.execute("drop view if exists %s" % v)
|
deck.db.execute("drop view if exists %s" % v)
|
||||||
# ensure all templates use the new style field format
|
|
||||||
for m in deck.allModels():
|
|
||||||
for t in m.templates:
|
|
||||||
t.qfmt = re.sub("%\((.+?)\)s", "{{\\1}}", t.qfmt)
|
|
||||||
t.afmt = re.sub("%\((.+?)\)s", "{{\\1}}", t.afmt)
|
|
||||||
m.flush()
|
|
||||||
# remove stats, as it's all in the revlog now
|
# remove stats, as it's all in the revlog now
|
||||||
deck.db.execute("drop table if exists stats")
|
deck.db.execute("drop table if exists stats")
|
||||||
# suspended cards don't use ranges anymore
|
# suspended cards don't use ranges anymore
|
||||||
|
|
|
@ -52,7 +52,7 @@ def test_factAddDelete():
|
||||||
f = deck.newFact()
|
f = deck.newFact()
|
||||||
f['Front'] = u"one"; f['Back'] = u"two"
|
f['Front'] = u"one"; f['Back'] = u"two"
|
||||||
m = f.model
|
m = f.model
|
||||||
m.templates[1].active = True
|
m.templates[1]['actv'] = True
|
||||||
m.flush()
|
m.flush()
|
||||||
n = deck.addFact(f)
|
n = deck.addFact(f)
|
||||||
assert n == 2
|
assert n == 2
|
||||||
|
|
|
@ -74,7 +74,7 @@ def test_db():
|
||||||
# modify template & regenerate
|
# modify template & regenerate
|
||||||
assert deck.db.scalar("select count() from media") == 1
|
assert deck.db.scalar("select count() from media") == 1
|
||||||
m = deck.currentModel()
|
m = deck.currentModel()
|
||||||
m.templates[0].afmt=u'<img src="{{{Back}}}">'
|
m.templates[0]['afmt']=u'<img src="{{{Back}}}">'
|
||||||
m.flush()
|
m.flush()
|
||||||
deck.renderQA(type="all")
|
deck.renderQA(type="all")
|
||||||
assert deck.db.scalar("select count() from media") == 2
|
assert deck.db.scalar("select count() from media") == 2
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from tests.shared import getEmptyDeck
|
from tests.shared import getEmptyDeck
|
||||||
from anki.models import Model, Template
|
from anki.models import Model
|
||||||
from anki.utils import stripHTML
|
from anki.utils import stripHTML
|
||||||
|
|
||||||
def test_modelDelete():
|
def test_modelDelete():
|
||||||
|
@ -20,7 +20,6 @@ def test_modelCopy():
|
||||||
m2 = m.copy()
|
m2 = m.copy()
|
||||||
assert m2.name == "Basic copy"
|
assert m2.name == "Basic copy"
|
||||||
assert m2.id != m.id
|
assert m2.id != m.id
|
||||||
assert m2.templates[0].id != m.templates[0].id
|
|
||||||
assert len(m2.fields) == 2
|
assert len(m2.fields) == 2
|
||||||
assert len(m.fields) == 2
|
assert len(m.fields) == 2
|
||||||
assert len(m2.fields) == len(m.fields)
|
assert len(m2.fields) == len(m.fields)
|
||||||
|
|
|
@ -32,7 +32,7 @@ def test_new():
|
||||||
# the default order should ensure siblings are not seen together, and
|
# the default order should ensure siblings are not seen together, and
|
||||||
# should show all cards
|
# should show all cards
|
||||||
m = d.currentModel()
|
m = d.currentModel()
|
||||||
m.templates[1].active = True
|
m.templates[1]['actv'] = True
|
||||||
m.flush()
|
m.flush()
|
||||||
f = d.newFact()
|
f = d.newFact()
|
||||||
f['Front'] = u"2"; f['Back'] = u"2"
|
f['Front'] = u"2"; f['Back'] = u"2"
|
||||||
|
|
Loading…
Reference in a new issue