Use scrolling list of checkboxes for dependencies on submit form

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2013-02-25 10:58:24 +00:00
parent 3964071e9d
commit cbeba65dac
4 changed files with 94 additions and 2 deletions

View File

@ -8,6 +8,7 @@ from layerindex.models import LayerItem, LayerMaintainer
from django import forms from django import forms
from django.core.validators import URLValidator, RegexValidator, email_re from django.core.validators import URLValidator, RegexValidator, email_re
from django.forms.models import inlineformset_factory from django.forms.models import inlineformset_factory
from widgets import TableCheckboxSelectMultiple
import re import re
@ -40,7 +41,7 @@ LayerMaintainerFormSet = inlineformset_factory(LayerItem, LayerMaintainer, form=
class SubmitLayerForm(forms.ModelForm): class SubmitLayerForm(forms.ModelForm):
# Additional form fields # Additional form fields
deps = forms.ModelMultipleChoiceField(label='Other layers this layer depends upon', queryset=LayerItem.objects.all(), required=False) deps = forms.ModelMultipleChoiceField(label='Other layers this layer depends upon', queryset=LayerItem.objects.all(), required=False, widget=TableCheckboxSelectMultiple, initial=[l.pk for l in LayerItem.objects.filter(name='openembedded-core')])
class Meta: class Meta:
model = LayerItem model = LayerItem
@ -58,6 +59,16 @@ class SubmitLayerForm(forms.ModelForm):
raise forms.ValidationError("Name cannot contain consecutive dashes") raise forms.ValidationError("Name cannot contain consecutive dashes")
return name return name
def clean_summary(self):
# Compress whitespace and use only spaces
summary = self.cleaned_data['summary'].strip()
summary = re.sub('\s+', ' ', summary)
return summary
def clean_description(self):
description = self.cleaned_data['description'].strip()
return description
def clean_vcs_url(self): def clean_vcs_url(self):
url = self.cleaned_data['vcs_url'].strip() url = self.cleaned_data['vcs_url'].strip()
val = RegexValidator(regex=r'[a-z]+://.*', message='Please enter a valid repository URL, e.g. git://server.name/path') val = RegexValidator(regex=r'[a-z]+://.*', message='Please enter a valid repository URL, e.g. git://server.name/path')

View File

@ -54,3 +54,9 @@ textarea {
h1 .btn { h1 .btn {
font-weight: normal; font-weight: normal;
} }
.scrolling {
height: auto;
max-height: 120px;
overflow: auto;
}

View File

@ -28,7 +28,13 @@
<div class="fieldWrapper"> <div class="fieldWrapper">
{{ field.errors }} {{ field.errors }}
{{ field.label_tag }} {{ field.label_tag }}
{{ field }} {% if field.name = 'deps' %}
<div class="scrolling">
{{ field }}
</div>
{% else %}
{{ field }}
{% endif %}
{{ field.help_text }} {{ field.help_text }}
</div> </div>
{% endfor %} {% endfor %}

69
layerindex/widgets.py Normal file
View File

@ -0,0 +1,69 @@
# Based on parts of forms/widgets.py from Django
#
# Copyright (c) Django Software Foundation and individual contributors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of Django nor the names of its contributors may be used
# to endorse or promote products derived from this software without
# specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import django.forms
from django.forms.widgets import CheckboxInput
from django.utils.encoding import force_unicode
from django.utils.html import escape, conditional_escape
from django.utils.safestring import mark_safe
from itertools import chain
# Reworked CheckboxSelectMultiple
class TableCheckboxSelectMultiple(django.forms.SelectMultiple):
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
has_id = attrs and 'id' in attrs
final_attrs = self.build_attrs(attrs, name=name)
output = [u'<table>']
# Normalize to strings
str_values = set([force_unicode(v) for v in value])
for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
# If an ID attribute was given, add a numeric index as a suffix,
# so that the checkboxes don't all have the same ID attribute.
if has_id:
final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
label_for = u' for="%s"' % final_attrs['id']
else:
label_for = ''
cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
option_value = force_unicode(option_value)
rendered_cb = cb.render(name, option_value)
option_label = conditional_escape(force_unicode(option_label))
output.append(u'<tr><td>%s</td><td><label%s>%s</label></td></tr>' % (rendered_cb, label_for, option_label))
output.append(u'</table>')
return mark_safe(u'\n'.join(output))
def id_for_label(self, id_):
# See the comment for RadioSelect.id_for_label()
if id_:
id_ += '_0'
return id_