Merge pull request #34 from MELScience/widget_refactor

Use template-based widget rendering in AdminLocalizedFieldWidget
This commit is contained in:
Swen Kooij 2017-07-18 09:39:00 +03:00 committed by GitHub
commit d5f43c783a
4 changed files with 75 additions and 40 deletions

View File

@ -1,14 +1,16 @@
{% with widget_id=widget.attrs.id %}
<div class="localized-fields-widget" role="tabs" data-synctabs="translation"> <div class="localized-fields-widget" role="tabs" data-synctabs="translation">
<ul class="localized-fields-widget tabs"> <ul class="localized-fields-widget tabs">
{% for key, lang in available_languages %} {% for widget in widget.subwidgets %}
<li class="localized-fields-widget tab"> <li class="localized-fields-widget tab">
<a href="#{{ id }}_{{ key }}">{{ lang|capfirst }}</a> <a href="#{{ widget_id }}_{{ widget.attrs.lang_code }}">{{ widget.attrs.lang_name|capfirst }}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% for key, widget in widgets %} {% for widget in widget.subwidgets %}
<div role="tabpanel" id="{{ id }}_{{ key }}"> <div role="tabpanel" id="{{ widget_id }}_{{ widget.attrs.lang_code }}">
{{ widget }} {% include widget.template_name %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% endwith %}

View File

@ -3,7 +3,6 @@ from typing import List
from django.conf import settings from django.conf import settings
from django import forms from django import forms
from django.contrib.admin import widgets from django.contrib.admin import widgets
from django.template.loader import render_to_string
from .value import LocalizedValue from .value import LocalizedValue
@ -49,54 +48,37 @@ class LocalizedFieldWidget(forms.MultiWidget):
return result return result
def get_context(self, name, value, attrs):
class LocalizedCharFieldWidget(LocalizedFieldWidget): context = super(forms.MultiWidget, self).get_context(name, value, attrs)
"""Widget that has an input box for every language."""
widget = forms.TextInput
class LocalizedFileWidget(LocalizedFieldWidget):
"""Widget that has an file input box for every language."""
widget = forms.ClearableFileInput
class AdminLocalizedFieldWidget(LocalizedFieldWidget):
widget = widgets.AdminTextareaWidget
template = 'localized_fields/admin/widget.html'
def render(self, name, value, attrs=None):
if self.is_localized: if self.is_localized:
for widget in self.widgets: for widget in self.widgets:
widget.is_localized = self.is_localized widget.is_localized = self.is_localized
# value is a list of values, each corresponding to a widget # value is a list of values, each corresponding to a widget
# in self.widgets. # in self.widgets.
if not isinstance(value, list): if not isinstance(value, list):
value = self.decompress(value) value = self.decompress(value)
output = [] final_attrs = context['widget']['attrs']
final_attrs = self.build_attrs(attrs) input_type = final_attrs.pop('type', None)
id_ = final_attrs.get('id') id_ = final_attrs.get('id')
subwidgets = []
for i, widget in enumerate(self.widgets): for i, widget in enumerate(self.widgets):
if input_type is not None:
widget.input_type = input_type
widget_name = '%s_%s' % (name, i)
try: try:
widget_value = value[i] widget_value = value[i]
except IndexError: except IndexError:
widget_value = None widget_value = None
if id_: if id_:
final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) widget_attrs = final_attrs.copy()
widget_attrs['id'] = '%s_%s' % (id_, i)
widget_attrs = self.build_widget_attrs(widget, widget_value, final_attrs) else:
output.append(widget.render(name + '_%s' % i, widget_value, widget_attrs)) widget_attrs = final_attrs
widget_attrs = self.build_widget_attrs(widget, widget_value, widget_attrs)
context = { subwidgets.append(widget.get_context(widget_name, widget_value, widget_attrs)['widget'])
'id': final_attrs.get('id'), context['widget']['subwidgets'] = subwidgets
'name': name, return context
'widgets': zip([code for code, lang in settings.LANGUAGES], output),
'available_languages': settings.LANGUAGES
}
return render_to_string(self.template, context)
@staticmethod @staticmethod
def build_widget_attrs(widget, value, attrs): def build_widget_attrs(widget, value, attrs):
@ -109,6 +91,21 @@ class AdminLocalizedFieldWidget(LocalizedFieldWidget):
return attrs return attrs
class LocalizedCharFieldWidget(LocalizedFieldWidget):
"""Widget that has an input box for every language."""
widget = forms.TextInput
class LocalizedFileWidget(LocalizedFieldWidget):
"""Widget that has an file input box for every language."""
widget = forms.ClearableFileInput
class AdminLocalizedFieldWidget(LocalizedFieldWidget):
template_name = 'localized_fields/admin/widget.html'
widget = widgets.AdminTextareaWidget
class AdminLocalizedCharFieldWidget(AdminLocalizedFieldWidget): class AdminLocalizedCharFieldWidget(AdminLocalizedFieldWidget):
widget = widgets.AdminTextInputWidget widget = widgets.AdminTextInputWidget

24
tests/test_file_widget.py Normal file
View File

@ -0,0 +1,24 @@
from django.test import TestCase
from localized_fields.value import LocalizedFileValue
from localized_fields.widgets import LocalizedFileWidget
class LocalizedFileWidgetTestCase(TestCase):
"""Tests the workings of the :see:LocalizedFiledWidget class."""
@staticmethod
def test_get_context():
"""Tests whether the :see:get_context correctly
handles 'required' attribute, separately for each subwidget."""
widget = LocalizedFileWidget()
widget.widgets[0].is_required = True
widget.widgets[1].is_required = True
widget.widgets[2].is_required = False
context = widget.get_context(name='test',
value=LocalizedFileValue(dict(en='test')),
attrs=dict(required=True))
assert 'required' not in context['widget']['subwidgets'][0]['attrs']
assert context['widget']['subwidgets'][1]['attrs']['required']
assert 'required' not in context['widget']['subwidgets'][2]['attrs']

View File

@ -44,6 +44,19 @@ class LocalizedFieldWidgetTestCase(TestCase):
for _, value in zip(settings.LANGUAGES, decompressed_values): for _, value in zip(settings.LANGUAGES, decompressed_values):
assert not value assert not value
@staticmethod
def test_get_context():
"""Tests whether the :see:get_context correctly
handles 'required' attribute, separately for each subwidget."""
widget = LocalizedFieldWidget()
widget.widgets[0].is_required = True
widget.widgets[1].is_required = False
context = widget.get_context(name='test', value=LocalizedValue(),
attrs=dict(required=True))
assert context['widget']['subwidgets'][0]['attrs']['required']
assert 'required' not in context['widget']['subwidgets'][1]['attrs']
@staticmethod @staticmethod
def test_render(): def test_render():
"""Tests whether the :see:LocalizedFieldWidget correctly """Tests whether the :see:LocalizedFieldWidget correctly
@ -52,4 +65,3 @@ class LocalizedFieldWidgetTestCase(TestCase):
widget = LocalizedFieldWidget() widget = LocalizedFieldWidget()
output = widget.render(name='title', value=None) output = widget.render(name='title', value=None)
assert bool(re.search('<label (.|\n|\t)*>\w+<\/label>', output)) assert bool(re.search('<label (.|\n|\t)*>\w+<\/label>', output))