mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 06:52:21 -04:00

The model now has a css column, and when it's flushed, it generates the css for the fields and templates. This means we don't have to generate the CSS on deck load anymore. The hex cache has also been removed. Javascript couldn't handle big ints, but since ints are small numbers now, we no longer need a cache to efficiently convert an id to hex.
196 lines
5.3 KiB
Python
196 lines
5.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright: Damien Elmes <anki@ichi2.net>
|
|
# License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html
|
|
|
|
import simplejson
|
|
from anki.utils import intTime, hexifyID
|
|
from anki.fonts import toPlatformFont
|
|
from anki.lang import _
|
|
|
|
# Models
|
|
##########################################################################
|
|
|
|
defaultConf = {
|
|
}
|
|
|
|
class Model(object):
|
|
|
|
def __init__(self, deck, id=None):
|
|
self.deck = deck
|
|
if id:
|
|
self.id = id
|
|
self.load()
|
|
else:
|
|
self.id = None
|
|
self.name = u""
|
|
self.mod = intTime()
|
|
self.conf = defaultConf.copy()
|
|
self.css = ""
|
|
self.fields = []
|
|
self.templates = []
|
|
|
|
def load(self):
|
|
(self.mod,
|
|
self.name,
|
|
self.fields,
|
|
self.conf) = self.deck.db.first("""
|
|
select mod, name, flds, conf from models where id = ?""", self.id)
|
|
self.fields = simplejson.loads(self.fields)
|
|
self.conf = simplejson.loads(self.conf)
|
|
self.loadTemplates()
|
|
|
|
def flush(self):
|
|
self.mod = intTime()
|
|
ret = self.deck.db.execute("""
|
|
insert or replace into models values (?, ?, ?, ?, ?, ?)""",
|
|
self.id, self.mod, self.name,
|
|
simplejson.dumps(self.fields),
|
|
simplejson.dumps(self.conf),
|
|
self.genCSS())
|
|
self.id = ret.lastrowid
|
|
[t._flush() for t in self.templates]
|
|
|
|
def updateCache(self):
|
|
self.deck.updateCache([self.id], "model")
|
|
|
|
def _getID(self):
|
|
if not self.id:
|
|
# flush so we can get our DB id
|
|
self.flush()
|
|
return self.id
|
|
|
|
# Fields
|
|
##################################################
|
|
|
|
def newField(self):
|
|
return defaultFieldConf.copy()
|
|
|
|
def addField(self, field):
|
|
self.deck.modSchema()
|
|
self.fields.append(field)
|
|
|
|
def fieldMap(self):
|
|
"Mapping of field name -> (ord, conf)."
|
|
return dict([(f['name'], (c, f)) for c, f in enumerate(self.fields)])
|
|
|
|
def sortField(self):
|
|
return 0
|
|
|
|
# Templates
|
|
##################################################
|
|
|
|
def loadTemplates(self):
|
|
sql = "select * from templates where mid = ? order by ord"
|
|
self.templates = [Template(self.deck, data)
|
|
for data in self.deck.db.all(sql, self.id)]
|
|
|
|
def addTemplate(self, template):
|
|
self.deck.modSchema()
|
|
template.mid = self._getID()
|
|
template.ord = len(self.templates)
|
|
self.templates.append(template)
|
|
|
|
# Copying
|
|
##################################################
|
|
|
|
def copy(self):
|
|
"Copy, flush and return."
|
|
new = Model(self.deck, self.id)
|
|
new.id = None
|
|
new.name += _(" copy")
|
|
new.fields = [f.copy() for f in self.fields]
|
|
# get new id
|
|
t = new.templates; new.templates = []
|
|
new.flush()
|
|
# then put back
|
|
new.templates = t
|
|
for t in new.templates:
|
|
t.id = None
|
|
t.mid = new.id
|
|
t._flush()
|
|
return new
|
|
|
|
# CSS generation
|
|
##################################################
|
|
|
|
def genCSS(self):
|
|
# fields
|
|
css = "".join([self._fieldCSS(
|
|
".fm%s.%s" % (hexifyID(self.id), hexifyID(c)),
|
|
(f['font'], f['qsize'], f['qcol'], f['rtl'], f['pre']))
|
|
for c, f in enumerate(self.fields)])
|
|
# templates
|
|
for t in 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
|
|
|
|
def _fieldCSS(self, prefix, row):
|
|
(fam, siz, col, rtl, pre) = row
|
|
t = 'font-family:"%s";' % toPlatformFont(fam)
|
|
t += 'font-size:%dpx;' % siz
|
|
t += 'color:%s;' % col
|
|
if rtl:
|
|
t += "direction:rtl;unicode-bidi:embed;"
|
|
if pre:
|
|
t += "white-space:pre-wrap;"
|
|
t = "%s {%s}\n" % (prefix, 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,
|
|
}
|
|
|
|
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
|