1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
import json
from django.db import models
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
class TableFormatter(object):
"""
Table formatter which should convert a structure of nested lists into
a suitable HTML table representation.
"""
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def __call__(self, data):
return self.format_table(data)
def format_table(self, data):
return u'<table class="table">%s</table>' % u''.join(
self.format_row(index, row) for index, row in enumerate(data))
def format_row(self, index, row):
self.row_index = index
return u'<tr>%s</tr>' % u''.join(
self.format_cell(index, cell) for index, cell in enumerate(row))
def format_cell(self, index, cell):
return u'<td>%s</td>' % cell
class TitleTableFormatter(TableFormatter):
"""
TitleTableFormatter(first_row_title=True, first_column_title=True)
"""
def format_cell(self, index, cell):
if (not self.row_index and getattr(self, 'first_row_title', True)) or \
(not index and getattr(self, 'first_column_title', True)):
return u'<th>%s</th>' % cell
return u'<td>%s</td>' % cell
class TableContent(models.Model):
"""
Content to edit and display HTML tables in the CMS.
The standard rich text editor configuration in FeinCMS does not activate
the table plugin. This content type can be used to edit and display
nicely formatted HTML tables. It is easy to specify your own table
renderers.
"""
feincms_item_editor_includes = {
'head': ['admin/content/table/init.html'],
}
html = models.TextField('HTML', blank=True, editable=False)
DEFAULT_TYPES = [
('plain', _('plain'), TableFormatter()),
('titlerow', _('title row'), TitleTableFormatter(
first_row_title=True, first_column_title=False)),
('titlerowcol', _('title row and column'), TitleTableFormatter(
first_row_title=True, first_column_title=True)),
]
class Meta:
abstract = True
verbose_name = _('table')
verbose_name_plural = _('tables')
@classmethod
def initialize_type(cls, TYPES=None):
TYPES = TYPES or cls.DEFAULT_TYPES
cls.FORMATTERS = dict((t[0], t[2]) for t in TYPES)
cls.TYPE_CHOICES = [(t[0], t[1]) for t in TYPES]
cls.add_to_class('type', models.CharField(_('type'), max_length=20,
choices=cls.TYPE_CHOICES,
default=cls.TYPE_CHOICES[0][0]))
# Add after type, so that type comes before data in admin interface
cls.add_to_class('data', models.TextField(_('data'), blank=True))
def render(self, **kwargs):
return mark_safe(self.html)
def save(self, *args, **kwargs):
# XXX ugly, but otherwise the decoder raises exceptions
self.data = self.data.replace('\r', '\\r').replace('\n', '\\n').replace('\t', '\\t')
self.html = self.data and self.FORMATTERS[self.type](json.loads(self.data)) or u''
super(TableContent, self).save(*args, **kwargs)
|