mirror of
git://git.yoctoproject.org/layerindex-web.git
synced 2025-07-19 12:49:01 +02:00
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:
parent
3964071e9d
commit
cbeba65dac
|
@ -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')
|
||||||
|
|
|
@ -54,3 +54,9 @@ textarea {
|
||||||
h1 .btn {
|
h1 .btn {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scrolling {
|
||||||
|
height: auto;
|
||||||
|
max-height: 120px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
|
@ -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
69
layerindex/widgets.py
Normal 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_
|
Loading…
Reference in New Issue
Block a user