fields.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. from __future__ import absolute_import, unicode_literals
  2. import json
  3. from wagtail.utils.widgets import WidgetWithScript
  4. from wagtail.wagtailcore.blocks import FieldBlock
  5. from django.template.loader import render_to_string
  6. from django.utils.functional import cached_property
  7. from django.utils import translation
  8. from django import forms
  9. class TableInput(WidgetWithScript, forms.HiddenInput):
  10. def __init__(self, table_options=None, attrs=None):
  11. self.table_options = table_options
  12. super(TableInput, self).__init__(attrs=attrs)
  13. def render(self, name, value, attrs=None):
  14. original_field_html = super(TableInput, self).render(name, value, attrs)
  15. return render_to_string("table_block/widgets/table.html", {
  16. 'original_field_html': original_field_html,
  17. 'attrs': attrs,
  18. 'value': value,
  19. })
  20. def render_js_init(self, id_, name, value):
  21. return "initTable({0}, {1});".format(json.dumps(id_), json.dumps(self.table_options))
  22. class TableBlock(FieldBlock):
  23. def __init__(self, required=True, help_text=None, table_options=None, **kwargs):
  24. # CharField's 'label' and 'initial' parameters are not exposed, as Block handles that functionality
  25. # natively (via 'label' and 'default')
  26. # CharField's 'max_length' and 'min_length' parameters are not exposed as table data needs to
  27. # have arbitrary length
  28. # table_options can contain any valid handsontable options: http://docs.handsontable.com/0.18.0/Options.html
  29. self.field_options = {'required': required, 'help_text': help_text}
  30. language = translation.get_language()
  31. if language is not None and len(language) > 2:
  32. language = language[:2]
  33. default_table_options = {
  34. 'minSpareRows': 0,
  35. 'startRows': 3,
  36. 'startCols': 3,
  37. 'colHeaders': False,
  38. 'rowHeaders': False,
  39. 'contextMenu': True,
  40. 'editor': 'text',
  41. 'stretchH': 'all',
  42. 'height': 108,
  43. 'language': language,
  44. 'renderer': 'text',
  45. 'autoColumnSize': False,
  46. }
  47. if table_options is not None:
  48. default_table_options.update(table_options)
  49. self.table_options = default_table_options
  50. super(TableBlock, self).__init__(**kwargs)
  51. @cached_property
  52. def field(self):
  53. return forms.CharField(widget=TableInput(table_options=self.table_options), **self.field_options)
  54. def value_from_form(self, value):
  55. return json.loads(value)
  56. def value_for_form(self, value):
  57. return json.dumps(value)
  58. def is_html_renderer(self):
  59. return self.table_options['renderer'] == 'html'
  60. def render(self, value):
  61. template = getattr(self.meta, 'template', None)
  62. if template and value:
  63. table_header = value['data'][0] if value.get('data', None) and len(value['data']) > 0 and value.get('first_row_is_table_header', False) else None
  64. first_col_is_header = value.get('first_col_is_header', False)
  65. context = {
  66. 'self': value,
  67. self.TEMPLATE_VAR: value,
  68. 'table_header': table_header,
  69. 'first_col_is_header': first_col_is_header,
  70. 'html_renderer': self.is_html_renderer(),
  71. 'data': value['data'][1:] if table_header else value.get('data', [])
  72. }
  73. return render_to_string(template, context)
  74. else:
  75. return self.render_basic(value)
  76. @property
  77. def media(self):
  78. return forms.Media(
  79. css={'all': ['table_block/css/vendor/handsontable-0.24.2.full.min.css']},
  80. js=['table_block/js/vendor/handsontable-0.24.2.full.min.js', 'table_block/js/table.js']
  81. )
  82. class Meta:
  83. default = None
  84. template = 'table_block/blocks/table.html'