Integrate jquery formset.js properly.

This commit is contained in:
Jan Philipp Timme 2014-12-10 16:28:21 +01:00
parent c019b5f0b9
commit e7fc6dcb8a
8 changed files with 292 additions and 55 deletions

2
.gitignore vendored
View File

@ -4,5 +4,5 @@
*.pyc
citavi_mapper/private_settings.py
static/
/static/
media/*

View File

@ -81,21 +81,23 @@ class PersonMapForm(forms.Form):
global_identity = forms.ModelChoiceField(queryset=PersonGlobalIdentity.objects.all(), required=False)
preferred_identity = forms.BooleanField(initial=False, required=False)
""" FormHelper for the PresentationPersonForm"""
PresentationPersonFormHelper = FormHelper()
PresentationPersonFormHelper.form_tag = False
PresentationPersonFormHelper.label_class = u'col-lg-2'
PresentationPersonFormHelper.field_class = u'col-lg-4'
PresentationPersonFormHelper.layout = Layout(
u'given_name',
u'additional_name',
u'family_name',
u'hshmembership'
)
class PresentationPersonForm(forms.ModelForm):
""" Modelform for PresentationPerson """
def __init__(self, *args, **kwargs):
super(PresentationPersonForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.label_class = u'col-lg-2'
self.helper.field_class = u'col-lg-4'
self.helper.layout = Layout(
u'given_name',
u'additional_name',
u'family_name',
u'hshmembership'
)
self.helper = PresentationPersonFormHelper
given_name = forms.CharField(
label=u"Vorname",
@ -115,13 +117,10 @@ class PresentationPersonForm(forms.ModelForm):
required=True,
)
hshmembership = forms.ChoiceField(
choices=[
(u'yes', u'Ja'), #
(u'no', u'Nein'),
(u'maybe', u'Unbekannt'),
],
initial=u'yes',
hshmembership = forms.TypedChoiceField(
choices=((u'yes', u'Ja'), (u'no', u'Nein'), (u'maybe', u'Maybe')),
initial=u'maybe',
required=True,
widget=forms.RadioSelect()
)
@ -129,22 +128,27 @@ class PresentationPersonForm(forms.ModelForm):
model = PresentationPerson
fields = [u'given_name', u'additional_name', u'family_name', u'hshmembership']
class PresentationEventForm(forms.ModelForm):
""" Form for the PresentationEventModel"""
def __init__(self, *args, **kwargs):
super(PresentationEventForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.label_class = u'col-lg-2'
self.helper.field_class = u'col-lg-4'
self.helper.layout = Layout(
""" FormHelper for the PresentationEventForm"""
PresentationEventFormHelper = FormHelper()
PresentationEventFormHelper.form_tag = False
PresentationEventFormHelper.label_class = u'col-lg-2'
PresentationEventFormHelper.field_class = u'col-lg-4'
PresentationEventFormHelper.layout = Layout(
u'date',
u'name',
u'workshop',
u'place',
u'start_date',
u'end_date'
)
)
class PresentationEventForm(forms.ModelForm):
""" Form for the PresentationEventModel"""
def __init__(self, *args, **kwargs):
super(PresentationEventForm, self).__init__(*args, **kwargs)
self.helper = PresentationEventFormHelper
date = forms.DateField(
label=u"Datum",
required=True ,
@ -191,7 +195,7 @@ class PresentationForm(forms.ModelForm):
title = forms.CharField()
type = forms.ChoiceField(choices=[(u'new', u'Hauptvortrag'), (u'existing', u'andere Veranstaltung')], initial=u'new', widget=forms.RadioSelect())
abstract = forms.CharField()
abstract = forms.TextInput()
# Event (other event)
comments = forms.CharField()

View File

@ -1,11 +1,14 @@
from django import forms
from frontend.models import Presentation, PresentationEvent, PresentationPerson
from django.forms.models import inlineformset_factory
PresentationPersonInlineFormset = inlineformset_factory(
Presentation,
PresentationPerson,
extra=1,
can_delete=False
can_delete=False,
widgets={'hshmembership': forms.RadioSelect}
)
PresentationEventInlineFormset = inlineformset_factory(

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-2
from django.db import models
class Project(models.Model):
""" Model representing a citavi project. """
name = models.CharField(max_length=255)
@ -20,7 +20,7 @@ class Presentation(models.Model):
""" Presention Model for PresentationForm"""
title = models.CharField(max_length=255)
type = models.CharField(max_length=255)
abstract = models.CharField(max_length=255)
abstract = models.TextField()
class PresentationEvent(models.Model):
"""Veranstaltung"""
@ -37,7 +37,7 @@ class PresentationPerson(models.Model):
given_name = models.CharField(max_length=255)
additional_name = models.CharField(max_length=255)
family_name = models.CharField(max_length=255)
hshmembership = models.CharField(max_length=255)
hshmembership = models.CharField(max_length=255, choices=((u'yes', u'Ja'), (u'no', u'Nein'), (u'maybe', u'Maybe')), default=u'maybe')
presentation = models.ForeignKey(Presentation, blank=False, null=False, db_index=True)

View File

@ -0,0 +1,44 @@
/* logo alignment stuff*/
a.navbar-brand {
margin-top: -11px;
}
/* style for login form */
#frontend-loginform {
width: 300px;
margin-left: auto;
margin-right: auto;
margin-top: 50px;
}
.container {
width: auto;
/*max-width: 680px;*/
padding: 0 15px;
}
/* Footer text align */
.container .text-muted {
margin: 20px 0;
}
/* sticky footer */
html {
position: relative;
min-height: 100%;
}
body {
/* sticky footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* sticky footer height */
height: 60px;
background-color: #f5f5f5;
}

View File

@ -0,0 +1,171 @@
/**
* jQuery Formset 1.2
* @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
* @requires jQuery 1.2.6 or later
*
* Copyright (c) 2009, Stanislaus Madueke
* All rights reserved.
*
* Licensed under the New BSD License
* See: http://www.opensource.org/licenses/bsd-license.php
*/
;(function($) {
$.fn.formset = function(opts)
{
var options = $.extend({}, $.fn.formset.defaults, opts),
flatExtraClasses = options.extraClasses.join(' '),
$$ = $(this),
applyExtraClasses = function(row, ndx) {
if (options.extraClasses) {
row.removeClass(flatExtraClasses);
row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
}
},
updateElementIndex = function(elem, prefix, ndx) {
var idRegex = new RegExp('(' + prefix + '-\\d+-)|(^)'),
replacement = prefix + '-' + ndx + '-';
if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
},
hasChildElements = function(row) {
return row.find('input,select,textarea,label').length > 0;
},
insertDeleteLink = function(row) {
if (row.is('TR')) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
} else if (row.is('UL') || row.is('OL')) {
// If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item:
row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
}
row.find('a.' + options.deleteCssClass).click(function() {
var row = $(this).parents('.' + options.formCssClass),
del = row.find('input:hidden[id $= "-DELETE"]');
if (del.length) {
// We're dealing with an inline formset; rather than remove
// this form from the DOM, we'll mark it as deleted and hide
// it, then let Django handle the deleting:
del.val('on');
row.hide();
} else {
row.remove();
// Update the TOTAL_FORMS form count.
// Also update names and IDs for all remaining form controls so they remain in sequence:
var forms = $('.' + options.formCssClass).not('.formset-custom-template');
$('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
applyExtraClasses(forms.eq(i), i);
forms.eq(i).find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, i);
});
}
}
// If a post-delete callback was provided, call it with the deleted form:
if (options.removed) options.removed(row);
return false;
});
};
$$.each(function(i) {
var row = $(this),
del = row.find('input:checkbox[id $= "-DELETE"]');
if (del.length) {
// If you specify "can_delete = True" when creating an inline formset,
// Django adds a checkbox to each form in the formset.
// Replace the default checkbox with a hidden field:
del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
del.remove();
}
if (hasChildElements(row)) {
insertDeleteLink(row);
row.addClass(options.formCssClass);
applyExtraClasses(row, i);
}
});
if ($$.length) {
var addButton, template;
if (options.formTemplate) {
// If a form template was specified, we'll clone it to generate new form instances:
template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');
template.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, 2012);
});
insertDeleteLink(template);
} else {
// Otherwise, use the last form in the formset; this works much better if you've got
// extra (>= 1) forms (thnaks to justhamade for pointing this out):
template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
template.find('input:hidden[id $= "-DELETE"]').remove();
template.find('input,select,textarea,label').each(function() {
var elem = $(this);
// If this is a checkbox or radiobutton, uncheck it.
// This fixes Issue 1, reported by Wilson.Andrew.J:
if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false);
} else {
elem.val('');
}
});
}
// FIXME: Perhaps using $.data would be a better idea?
options.formTemplate = template;
if ($$.attr('tagName') == 'TR') {
// If forms are laid out as table rows, insert the
// "add" button in a new table row:
var numCols = $$.eq(0).children().length;
$$.parent().append('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>');
addButton = $$.parent().find('tr:last a');
addButton.parents('tr').addClass(options.formCssClass + '-add');
} else {
// Otherwise, insert it immediately after the last form:
$$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
addButton = $$.filter(':last').next();
}
addButton.click(function() {
console.log(options);
var formCount = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val()),
row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
buttonRow = $(this).parents('tr.' + options.formCssClass + '-add').get(0) || this;
applyExtraClasses(row, formCount);
row.insertBefore($(buttonRow)).show();
row.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, formCount);
});
$('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount + 1);
// If a post-add callback was supplied, call it with the added form:
if (options.added) options.added(row);
return false;
});
}
return $$;
}
/* Setup plugin defaults */
$.fn.formset.defaults = {
prefix: 'form', // The form prefix for your django formset
formTemplate: null, // The jQuery selection cloned to generate new form instances
addText: '[+] add another', // Text for the add link
deleteText: '[-] remove', // Text for the delete link
addCssClass: 'add-row', // CSS class applied to the add link
deleteCssClass: 'delete-row', // CSS class applied to the delete link
formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
added: null, // Function called each time a new form is added
removed: null // Function called each time a form is deleted
};
})(jQuery)

View File

@ -4,7 +4,10 @@
<script type="text/javascript">
$(function() {
$('#presentationform #presentationpersonformset').formset({
prefix: '{{ formset.prefix }}'
prefix: '{{ person_formset.prefix }}'
});
$('#presentationform #presentationeventformset').formset({
prefix: '{{ event_formset.prefix }}'
});
})
</script>
@ -15,25 +18,36 @@
<h2>Vortrag anlegen</h2>
<form method="POST" action="" class="form-horizontal" id="presentationform">
{% crispy presentation_form %}
<hr>
<h3>Personen</h3>
<p id="presentationpersonformset">
{% for form in person_formset.forms %}
<div>
<input id="id_{{ person_formset.prefix }}-TOTAL_FORMS" name="{{ person_formset.prefix }}-TOTAL_FORMS" type="hidden" value="1" />
<input id="id_{{ person_formset.prefix }}-INITIAL_FORMS" name="{{ person_formset.prefix }}-INITIAL_FORMS" type="hidden" value="0" />
<input id="id_{{ person_formset.prefix }}-MAX_NUM_FORMS" name="{{ person_formset.prefix }}-MAX_NUM_FORMS" type="hidden" value="1000" />
</div>
<div id="presentationpersonformset">
{% for person_form in person_formset.forms %}
<div class="person_form">
{% crispy form person_form.helper %}
{% crispy person_form person_formhelper %}
</div>
<hr>
{% endfor %}
[+]<br>
</p>
</div>
<h3>Veranstaltungen</h3>
<p id="presentationeventformset">
{% for form in event_formset.forms %}
<div class="event_form">
{% crispy form event_form.helper %}
<div>
<input id="id_{{ event_formset.prefix }}-TOTAL_FORMS" name="{{ event_formset.prefix }}-TOTAL_FORMS" type="hidden" value="1" />
<input id="id_{{ event_formset.prefix }}-INITIAL_FORMS" name="{{ event_formset.prefix }}-INITIAL_FORMS" type="hidden" value="0" />
<input id="id_{{ event_formset.prefix }}-MAX_NUM_FORMS" name="{{ event_formset.prefix }}-MAX_NUM_FORMS" type="hidden" value="1000" />
</div>
<div id="presentationeventformset">
{% for event_form in event_formset.forms %}
<div class="event_form">
{% crispy event_form event_formhelper %}
</div>
<hr>
{% endfor %}
[+]<br>
</p>
</div>
<br>
<input type="submit" class="btn btn-primary btn-default" value="Submit">
</form>
{% endblock %}

View File

@ -16,10 +16,9 @@ from django.core.urlresolvers import reverse
from frontend.forms import NewProjectForm, FileUploadForm, PersonMapForm
from frontend.forms import PresentationForm, PresentationEventForm, PresentationPersonForm
from frontend.forms import PresentationEventFormHelper, PresentationPersonFormHelper
from frontend.models import Presentation, PresentationEvent, PresentationPerson
from frontend.formsets import PresentationEventInlineFormset, PresentationPersonInlineFormset
from fancy_formsets.views import FormsetsView
from frontend.models import Project
@ -122,11 +121,13 @@ class HelloView(ProtectedTemplateView):
def get_context_data(self, **kwargs):
""" Add form + formsets to template context. """
kwargs[u'presentation_form'] = PresentationForm();
kwargs[u'person_formset'] = PresentationPersonInlineFormset(prefix='person');
kwargs[u'event_formset'] = PresentationEventInlineFormset(prefix='event');
kwargs[u'person_form'] = PresentationPersonForm();
kwargs[u'event_form'] = PresentationEventForm();
kwargs[u'presentation_form'] = PresentationForm()
person_formset = PresentationPersonInlineFormset(prefix='person')
event_formset = PresentationEventInlineFormset(prefix='event')
kwargs[u'person_formset'] = person_formset
kwargs[u'event_formset'] = event_formset
kwargs[u'person_formhelper'] = PresentationPersonFormHelper;
kwargs[u'event_formhelper'] = PresentationEventFormHelper;
return super(HelloView, self).get_context_data(**kwargs)