Revision 8a53465c

b/flowspec/forms.py
212 212
        else:
213 213
            raise forms.ValidationError('Cannot be empty')
214 214

  
215
RuleFormSet = modelformset_factory(Route, extra=2) 
215
RuleFormSet = modelformset_factory(Route) 
216 216

  
217 217
def value_list_to_list(valuelist):
218 218
    vl = []
b/static/js/jquery.formset.js
1
/**
2
 * jQuery Formset 1.3-pre
3
 * @author Stanislaus Madueke (stan DOT madueke AT gmail DOT com)
4
 * @requires jQuery 1.2.6 or later
5
 *
6
 * Copyright (c) 2009, Stanislaus Madueke
7
 * All rights reserved.
8
 *
9
 * Licensed under the New BSD License
10
 * See: http://www.opensource.org/licenses/bsd-license.php
11
 */
12
;(function($) {
13
    $.fn.formset = function(opts)
14
    {
15
        var options = $.extend({}, $.fn.formset.defaults, opts),
16
            flatExtraClasses = options.extraClasses.join(' '),
17
            totalForms = $('#id_' + options.prefix + '-TOTAL_FORMS'),
18
            maxForms = $('#id_' + options.prefix + '-MAX_NUM_FORMS'),
19
            childElementSelector = 'input,select,textarea,label,div',
20
            $$ = $(this),
21

  
22
            applyExtraClasses = function(row, ndx) {
23
                if (options.extraClasses) {
24
                    row.removeClass(flatExtraClasses);
25
                    row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
26
                }
27
            },
28

  
29
            updateElementIndex = function(elem, prefix, ndx) {
30
                var idRegex = new RegExp(prefix + '-(\\d+|__prefix__)-'),
31
                    replacement = prefix + '-' + ndx + '-';
32
                if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
33
                if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
34
                if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
35
            },
36

  
37
            hasChildElements = function(row) {
38
                return row.find(childElementSelector).length > 0;
39
            },
40

  
41
            showAddButton = function() {
42
                return maxForms.length == 0 ||   // For Django versions pre 1.2
43
                    (maxForms.val() == '' || (maxForms.val() - totalForms.val() > 0))
44
            },
45

  
46
            insertDeleteLink = function(row) {
47
                if (row.is('TR')) {
48
                    // If the forms are laid out in table rows, insert
49
                    // the remove button into the last table cell:
50
                    row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
51
                } else if (row.is('UL') || row.is('OL')) {
52
                    // If they're laid out as an ordered/unordered list,
53
                    // insert an <li> after the last list item:
54
                    row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
55
                } else {
56
                    // Otherwise, just insert the remove button as the
57
                    // last child element of the form's container:
58
                    row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
59
                }
60
                row.find('a.' + options.deleteCssClass).click(function() {
61
                    var row = $(this).parents('.' + options.formCssClass),
62
                        del = row.find('input:hidden[id $= "-DELETE"]'),
63
                        buttonRow = row.siblings("a." + options.addCssClass + ', .' + options.formCssClass + '-add'),
64
                        forms;
65
                    if (del.length) {
66
                        // We're dealing with an inline formset.
67
                        // Rather than remove this form from the DOM, we'll mark it as deleted
68
                        // and hide it, then let Django handle the deleting:
69
                        del.val('on');
70
                        row.hide();
71
                        forms = $('.' + options.formCssClass).not(':hidden');
72
                    } else {
73
                        row.remove();
74
                        // Update the TOTAL_FORMS count:
75
                        forms = $('.' + options.formCssClass).not('.formset-custom-template');
76
                        totalForms.val(forms.length);
77
                    }
78
                    for (var i=0, formCount=forms.length; i<formCount; i++) {
79
                        // Apply `extraClasses` to form rows so they're nicely alternating:
80
                        applyExtraClasses(forms.eq(i), i);
81
                        if (!del.length) {
82
                            // Also update names and IDs for all child controls (if this isn't
83
                            // a delete-able inline formset) so they remain in sequence:
84
                            forms.eq(i).find(childElementSelector).each(function() {
85
                                updateElementIndex($(this), options.prefix, i);
86
                            });
87
                        }
88
                    }
89
                    // Check if we need to show the add button:
90
                    if (buttonRow.is(':hidden') && showAddButton()) buttonRow.show();
91
                    // If a post-delete callback was provided, call it with the deleted form:
92
                    if (options.removed) options.removed(row);
93
                    return false;
94
                });
95
            };
96

  
97
        $$.each(function(i) {
98
            var row = $(this),
99
                del = row.find('input:checkbox[id $= "-DELETE"]');
100
            if (del.length) {
101
                // If you specify "can_delete = True" when creating an inline formset,
102
                // Django adds a checkbox to each form in the formset.
103
                // Replace the default checkbox with a hidden field:
104
                if (del.is(':checked')) {
105
                    // If an inline formset containing deleted forms fails validation, make sure
106
                    // we keep the forms hidden (thanks for the bug report and suggested fix Mike)
107
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" value="on" />');
108
                    row.hide();
109
                } else {
110
                    del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
111
                }
112
                // Hide any labels associated with the DELETE checkbox:
113
                $('label[for="' + del.attr('id') + '"]').hide();
114
                del.remove();
115
            }
116
            if (hasChildElements(row)) {
117
                row.addClass(options.formCssClass);
118
                if (row.is(':visible')) {
119
                    insertDeleteLink(row);
120
                    applyExtraClasses(row, i);
121
                }
122
            }
123
        });
124

  
125
        if ($$.length) {
126
            var hideAddButton = !showAddButton(),
127
                addButton, template;
128
            if (options.formTemplate) {
129
                // If a form template was specified, we'll clone it to generate new form instances:
130
                template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
131
                template.removeAttr('id').addClass(options.formCssClass + ' formset-custom-template');
132
                template.find(childElementSelector).each(function() {
133
                    updateElementIndex($(this), options.prefix, '__prefix__');
134
                });
135
                insertDeleteLink(template);
136
            } else {
137
                // Otherwise, use the last form in the formset; this works much better if you've got
138
                // extra (>= 1) forms (thnaks to justhamade for pointing this out):
139
                template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
140
                template.find('input:hidden[id $= "-DELETE"]').remove();
141
                // Clear all cloned fields, except those the user wants to keep (thanks to brunogola for the suggestion):
142
                template.find(childElementSelector).not(options.keepFieldValues).each(function() {
143
                    var elem = $(this);
144
                    // If this is a checkbox or radiobutton, uncheck it.
145
                    // This fixes Issue 1, reported by Wilson.Andrew.J:
146
                    if (elem.is('input:checkbox') || elem.is('input:radio')) {
147
                        elem.attr('checked', false);
148
                    } else {
149
                        elem.val('');
150
                    }
151
                });
152
            }
153
            // FIXME: Perhaps using $.data would be a better idea?
154
            options.formTemplate = template;
155

  
156
            if ($$.attr('tagName') == 'TR') {
157
                // If forms are laid out as table rows, insert the
158
                // "add" button in a new table row:
159
                var numCols = $$.eq(0).children().length,   // This is a bit of an assumption :|
160
                    buttonRow = $('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>')
161
                                .addClass(options.formCssClass + '-add');
162
                $$.parent().append(buttonRow);
163
                if (hideAddButton) buttonRow.hide();
164
                addButton = buttonRow.find('a');
165
            } else {
166
                // Otherwise, insert it immediately after the last form:
167
                $$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
168
                addButton = $$.filter(':last').next();
169
                if (hideAddButton) addButton.hide();
170
            }
171
            addButton.click(function() {
172
                var formCount = parseInt(totalForms.val()),
173
                    row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
174
                    buttonRow = $($(this).parents('tr.' + options.formCssClass + '-add').get(0) || this);
175
                applyExtraClasses(row, formCount);
176
                row.insertBefore(buttonRow).show();
177
                row.find(childElementSelector).each(function() {
178
                    updateElementIndex($(this), options.prefix, formCount);
179
                });
180
                totalForms.val(formCount + 1);
181
                // Check if we've exceeded the maximum allowed number of forms:
182
                if (!showAddButton()) buttonRow.hide();
183
                // If a post-add callback was supplied, call it with the added form:
184
                if (options.added) options.added(row);
185
                return false;
186
            });
187
        }
188

  
189
        return $$;
190
    }
191

  
192
    /* Setup plugin defaults */
193
    $.fn.formset.defaults = {
194
        prefix: 'form',                  // The form prefix for your django formset
195
        formTemplate: null,              // The jQuery selection cloned to generate new form instances
196
        addText: 'add another',          // Text for the add link
197
        deleteText: 'remove',            // Text for the delete link
198
        addCssClass: 'add-row',          // CSS class applied to the add link
199
        deleteCssClass: 'delete-row',    // CSS class applied to the delete link
200
        formCssClass: 'dynamic-form',    // CSS class applied to each form in a formset
201
        extraClasses: [],                // Additional CSS classes, which will be applied to each form in turn
202
        keepFieldValues: '',             // jQuery selector for fields whose values should be kept when the form is cloned
203
        added: null,                     // Function called each time a new form is added
204
        removed: null                    // Function called each time a form is deleted
205
    };
206
})(jQuery)
b/templates/apply_set.html
17 17
	{% endif %}
18 18
		{% endblock %}
19 19
{% block extrahead %}
20
<script type="text/javascript" src="/static/js/jquery.formset.js"></script>
21
<script type="text/javascript">
22
           $(function() {
23
        	  $('.formset_class').formset({
24
        	  });
25
           })
26
       </script>
20 27
<script>
21 28
	$(document).ready( function(){
22
		
29
		//Initialize jquery formset
30
        
23 31
		$("#id_sourceport").css('width', '100px').attr('size', '5');
24 32
		$("#id_port").css('width', '100px').attr('size', '5');
25 33
		$("#id_destinationport").css('width', '100px').attr('size', '5');
......
142 150

  
143 151
<style type="text/css">
144 152
th {
145
	text-align: right;
146 153
	padding-right: 0.5em;
147 154
	vertical-align: top;
148 155
}
......
170 177
    margin: 15px auto;
171 178
    position: relative;
172 179
    text-align: center;
173
    width: 800px;
180
    /*width: 800px;*/
174 181
}
175 182

  
176 183
#rule_form_container input:not([type="submit"]), #rule_form_container select {
......
203 210
	background-color: #F9F9F9;
204 211
	border: 2px solid #FFFFFF;
205 212
	overflow: hidden;
206
    width: 800px;
213
    /*width: 800px;*/
207 214
	}
208 215
#rule_form_container div label {
209 216
    color: #666666;
......
225 232
input {
226 233
	width:100px;
227 234
}
235
textarea{
236
height: 63px;
237
    width: 174px;
238
}
239
.delete-row{
240
    background: url("/static/inline-delete.png") no-repeat scroll 0 50% transparent;
241
    outline: 0 none;
242
    padding-left: 16px;
243
}
228 244

  
229

  
245
.add-row {
246
    background: url("/static/icon_addlink.gif") no-repeat scroll 0 50% transparent;
247
    outline: 0 none;
248
    padding-left: 14px;
249
}
230 250
</style>
231 251
{% endblock %}
232 252
{% block content %}
......
237 257
            {% csrf_token %}
238 258
<table id="formset" class="form">
239 259
	  <thead><tr>
240
    <th>Name</th><th>Source</th><th>Destination</th><th>Then</th><th>Note</th>
260
    <th align="center">Name</th><th>Source</th><th>Destination</th><th>Protocol</th><th>SrcPort</th><th>DstPort</th><th>Port</th><th>Then</th><th>Note</th>
241 261
  </tr></thead>
242 262
{% for form in formset.forms %}
243 263
{{form.errors}}
244
<tr>
264
<tr class='formset_class'>
245 265
       <td>{{ form.name }}</td>
246 266
	   <td>{{ form.source }}</td>
247 267
	   <td>{{ form.destination }}</td>
268
	   <td>{{ form.protocol }}</td>
269
	   <td>{{ form.sourceport }}</td>
270
	   <td>{{ form.destinationport }}</td>
271
	   <td>{{ form.port }}</td>
248 272
	   <td>{{ form.then }}</td>
249 273
	   <td>{{ form.comments }}</td>
250 274
    </tr>
251 275
			{% endfor %}
252 276
	</table>
253

  
277
{{ formset.management_form }}
254 278
		<input type="submit" id="applybutton" value="{% trans "Apply" %}" />
255 279
    </form>
256 280
</div>

Also available in: Unified diff