diff --git a/wagtail/contrib/table_block/blocks.py b/wagtail/contrib/table_block/blocks.py
index 44fe079e94..c972101733 100644
--- a/wagtail/contrib/table_block/blocks.py
+++ b/wagtail/contrib/table_block/blocks.py
@@ -99,6 +99,13 @@ class TableBlock(FieldBlock):
'html_renderer': self.is_html_renderer(),
'data': value['data'][1:] if table_header else value.get('data', [])
})
+
+ if value.get('cell'):
+ new_context['classnames'] = {}
+ for meta in value['cell']:
+ if 'className' in meta:
+ new_context['classnames'][(meta['row'], meta['col'])] = meta['className']
+
return render_to_string(template, new_context)
else:
return self.render_basic(value, context=context)
diff --git a/wagtail/contrib/table_block/static/table_block/js/table.js b/wagtail/contrib/table_block/static/table_block/js/table.js
index b847838bbd..d53568bc91 100644
--- a/wagtail/contrib/table_block/static/table_block/js/table.js
+++ b/wagtail/contrib/table_block/static/table_block/js/table.js
@@ -10,10 +10,14 @@ function initTable(id, tableOptions) {
var hot;
var defaultOptions;
var finalOptions = {};
+ var getCellsClassnames;
var persist;
var cellEvent;
+ var metaEvent;
+ var initEvent;
var structureEvent;
var dataForForm = null;
+ var isInitialized = false;
var getWidth = function() {
return $('.widget-table_input').closest('.sequence-member-inner').width();
};
@@ -64,9 +68,26 @@ function initTable(id, tableOptions) {
});
}
+ getCellsClassnames = function() {
+ var meta = hot.getCellsMeta();
+ var cellsClassnames = []
+ for (var i = 0; i < meta.length; i++) {
+ if (meta[i].hasOwnProperty('className')) {
+ cellsClassnames.push({
+ row: meta[i].row,
+ col: meta[i].col,
+ className: meta[i].className
+ });
+ }
+ }
+ console.log(cellsClassnames);
+ return cellsClassnames;
+ };
+
persist = function() {
hiddenStreamInput.val(JSON.stringify({
data: hot.getData(),
+ cell: getCellsClassnames(),
first_row_is_table_header: tableHeaderCheckbox.prop('checked'),
first_col_is_header: colHeaderCheckbox.prop('checked')
}));
@@ -80,6 +101,16 @@ function initTable(id, tableOptions) {
persist();
};
+ metaEvent = function(row, column, key, value) {
+ if (isInitialized && key === 'className') {
+ persist();
+ }
+ };
+
+ initEvent = function() {
+ isInitialized = true;
+ };
+
structureEvent = function(index, amount) {
resizeHeight(getHeight());
persist();
@@ -99,12 +130,19 @@ function initTable(id, tableOptions) {
afterCreateRow: structureEvent,
afterRemoveCol: structureEvent,
afterRemoveRow: structureEvent,
+ afterSetCellMeta: metaEvent,
+ afterInit: initEvent,
// contextMenu set via init, from server defaults
};
- if (dataForForm !== null && dataForForm.hasOwnProperty('data')) {
+ if (dataForForm !== null) {
// Overrides default value from tableOptions (if given) with value from database
- defaultOptions.data = dataForForm.data;
+ if (dataForForm.hasOwnProperty('data')) {
+ defaultOptions.data = dataForForm.data;
+ }
+ if (dataForForm.hasOwnProperty('cell')) {
+ defaultOptions.cell = dataForForm.cell;
+ }
}
Object.keys(defaultOptions).forEach(function (key) {
diff --git a/wagtail/contrib/table_block/templates/table_block/blocks/table.html b/wagtail/contrib/table_block/templates/table_block/blocks/table.html
index e7d6f7cb01..766b3e7dfe 100644
--- a/wagtail/contrib/table_block/templates/table_block/blocks/table.html
+++ b/wagtail/contrib/table_block/templates/table_block/blocks/table.html
@@ -1,9 +1,12 @@
+{% load table_block_tags %}
+
{% if table_header %}
{% for column in table_header %}
-
+ {% with forloop.counter0 as col_index %}
+ |
{% if column.strip %}
{% if html_renderer %}
{{ column.strip|safe|linebreaksbr }}
@@ -12,16 +15,19 @@
{% endif %}
{% endif %}
|
+ {% endwith %}
{% endfor %}
{% endif %}
{% for row in data %}
+ {% with forloop.counter0 as row_index %}
{% for column in row %}
+ {% with forloop.counter0 as col_index %}
{% if first_col_is_header and forloop.first %}
-
+ |
{% if column.strip %}
{% if html_renderer %}
{{ column.strip|safe|linebreaksbr }}
@@ -31,7 +37,7 @@
{% endif %}
|
{% else %}
-
+ |
{% if column.strip %}
{% if html_renderer %}
{{ column.strip|safe|linebreaksbr }}
@@ -41,8 +47,10 @@
{% endif %}
|
{% endif %}
+ {% endwith %}
{% endfor %}
+ {% endwith %}
{% endfor %}
diff --git a/wagtail/contrib/table_block/templatetags/__init__.py b/wagtail/contrib/table_block/templatetags/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/wagtail/contrib/table_block/templatetags/table_block_tags.py b/wagtail/contrib/table_block/templatetags/table_block_tags.py
new file mode 100644
index 0000000000..5f84fad17a
--- /dev/null
+++ b/wagtail/contrib/table_block/templatetags/table_block_tags.py
@@ -0,0 +1,17 @@
+from django import template
+from django.utils.safestring import mark_safe
+
+register = template.Library()
+
+
+@register.simple_tag(takes_context=True)
+def cell_classname(context, row_index, col_index, table_header=None):
+ classnames = context.get('classnames')
+ if classnames:
+ if table_header is not None:
+ row_index += 1
+ index = (row_index, col_index)
+ cell_class = classnames.get(index)
+ if cell_class:
+ return mark_safe('class="{}"'.format(cell_class))
+ return ''
diff --git a/wagtail/contrib/table_block/tests.py b/wagtail/contrib/table_block/tests.py
index ac064251ec..fab7674f37 100644
--- a/wagtail/contrib/table_block/tests.py
+++ b/wagtail/contrib/table_block/tests.py
@@ -11,6 +11,19 @@ from wagtail.tests.testapp.models import TableBlockStreamPage
from wagtail.tests.utils import WagtailTestUtils
+def get_cell_classname(cells_meta, row_index, col_index):
+ """
+ Helper function used in building a test html
+ table. Provides a cell's class attribute if
+ one is specified in the meta.
+ """
+ if cells_meta:
+ for meta in cells_meta:
+ if meta.get('row') == row_index and meta.get('col') == col_index:
+ return ' class="%s"' % meta.get('className')
+ return ''
+
+
def tiny_escape(val):
"""
Helper function used in building a test html
@@ -26,22 +39,24 @@ def get_test_html_from_value(value):
that's what we expect from the TableBlock.
"""
data = list(value['data']) # Make a copy
+ meta = value.get('cell')
table = ''
if value['first_row_is_table_header']:
row_header = data.pop(0)
table += ''
- for th in row_header:
- table += '%s | ' % tiny_escape(th)
+ for col_idx, th in enumerate(row_header):
+ table += '%s | ' % (get_cell_classname(meta, 0, col_idx), tiny_escape(th))
table += '
'
table += ''
- for row in data:
+ row_idx_start = 1 if value['first_row_is_table_header'] else 0
+ for row_idx, row in enumerate(data, row_idx_start):
table += ''
first = True
- for col in row:
+ for col_idx, col in enumerate(row):
if value['first_col_is_header'] and first:
- table += '%s | ' % tiny_escape(col)
+ table += '%s | ' % (get_cell_classname(meta, row_idx, col_idx), tiny_escape(col))
else:
- table += '%s | ' % tiny_escape(col)
+ table += '%s | ' % (get_cell_classname(meta, row_idx, col_idx), tiny_escape(col))
first = False
table += '
'
table += '
'
@@ -89,6 +104,22 @@ class TestTableBlock(TestTableBlockRenderingBase):
self.assertHTMLEqual(result, expected)
self.assertIn('Test 2', result)
+ def test_table_block_aligment_render(self):
+ """
+ Test a generic render with some cells aligned.
+ """
+ value = {'first_row_is_table_header': True, 'first_col_is_header': False,
+ 'cell': [{'row': 0, 'col': 1, 'className': 'htLeft'},
+ {'row': 1, 'col': 1, 'className': 'htRight'}],
+ 'data': [['Test 1', 'Test 2', 'Test 3'], [None, None, None],
+ [None, None, None]]}
+ block = TableBlock()
+ result = block.render(value)
+ expected = get_test_html_from_value(value)
+
+ self.assertHTMLEqual(result, expected)
+ self.assertIn('Test 2', result)
+
def test_render_empty_table(self):
"""
An empty table should render okay.