diff --git a/cyder/base/views.py b/cyder/base/views.py index a556c4ce3..c839ec9e7 100644 --- a/cyder/base/views.py +++ b/cyder/base/views.py @@ -459,10 +459,10 @@ def table_update(request, pk, obj_type=None): Klass, FormKlass = get_klasses(obj_type) obj = get_object_or_404(Klass, pk=pk) - if not perm_soft(request, ACTION_UPDATE, obj=obj): - return HttpResponse(json.dumps({'error': 'You do not have appropriate' - ' permissions.'})) + return HttpResponse(json.dumps({ + 'error': {'__all__': [u'You do not have' + ' appropriate permissions.']}})) # DNS specific. qd = request.POST.copy() @@ -472,11 +472,22 @@ def table_update(request, pk, obj_type=None): # Call prune tree later if error, else domain leak. label, domain = ensure_label_domain(fqdn) except ValidationError, e: - return HttpResponse(json.dumps({'error': e.messages})) + return HttpResponse( + json.dumps({'error': {'__all__': [e.messages]}})) qd['label'], qd['domain'] = label, str(domain.pk) form = FormKlass(qd, instance=obj) + # Set the fields that weren't modified + for key in form.fields: + if key not in qd: + old_value = form.initial[key] + if isinstance(old_value, list): + # ManyToManyFields need special treatment + form.data.setlist(key, old_value) + else: + form.data[key] = old_value + if form.is_valid(): form.save() return HttpResponse() - return HttpResponse(json.dumps({'error': form.errors})) + return HttpResponse(json.dumps({'error': (form.errors)})) diff --git a/cyder/cydhcp/vlan/models.py b/cyder/cydhcp/vlan/models.py index 9fd3e7244..a26d70a47 100644 --- a/cyder/cydhcp/vlan/models.py +++ b/cyder/cydhcp/vlan/models.py @@ -50,7 +50,7 @@ def details(self): """For tables.""" data = super(Vlan, self).details() data['data'] = [ - ('Name', 'name', self), + ('Name', 'name', self.name), ('Number', 'number', self.number), ] return data diff --git a/cyder/templates/base/list.html b/cyder/templates/base/list.html index f498c18be..33655531c 100644 --- a/cyder/templates/base/list.html +++ b/cyder/templates/base/list.html @@ -37,7 +37,7 @@
diff --git a/media/js/tables.js b/media/js/tables.js index 67d0b7f20..1911fd35f 100755 --- a/media/js/tables.js +++ b/media/js/tables.js @@ -1,14 +1,12 @@ function cleanTablesForEditableGrid() { // Remove Action column. - if ($('th:contains("Actions")')) { - $('th:contains("Actions")').remove(); - $('td:last-child').remove(); + if ($('.actions_column')) { + $('.actions_column').remove(); } // Remove Info column. - if ($('th:contains("Info")')) { - $('th:contains("Info")').remove(); - $('td:first-child').remove(); + if ($('.info_column')) { + $('.info_column').remove(); } // Strip links and paragraph tags, remove table cell markdown until @@ -40,8 +38,9 @@ function editableGridCallback(rowIndex, columnIndex, oldValue, newValue, row) { } -function enableEditableGrid() { +function enableEditableGrid( allPostData ) { var $eg = $('#eg'); + var csrfToken = $('#view-metadata').attr('data-csrfToken'); if (!$eg) { return; } @@ -49,27 +48,99 @@ function enableEditableGrid() { cleanTablesForEditableGrid(); editableGrid = new EditableGrid("My Editable Grid"); editableGrid.loadJSONFromString($eg.attr('data-metadata')); - editableGrid.modelChanged = editableGridCallback; + editableGrid.modelChanged = function(rowIndex, columnIndex, oldValue, newValue, row) { + /* + Callback function on change. Send whatever was changed so the change + can be validated and the object can be updated. + */ + var postData = {}; + var data = {}; + postData[editableGrid.getColumnName(columnIndex)] = newValue; + postData['csrfmiddlewaretoken'] = csrfToken; + data['row'] = row; + data['postData'] = postData; + data['url'] = $(row).attr('data-url'); + data['oldValue'] = oldValue; + data['newValue'] = newValue; + allPostData[rowIndex + '-' + columnIndex] = data; + }; editableGrid.attachToHTMLTable('egtable'); editableGrid.renderGrid(); } $(document).ready(function() { + $.ajaxSetup({async:false}); + var allPostData = {}; var $enableEg = $('#enable-eg'); if ($enableEg.length) { $enableEg[0].reset(); + $('.exit-spreadsheet').click( function(e) { + e.preventDefault(); + if (confirm('Are you sure you want to exit spreadsheet mode? ' + + 'Your changes will not be submitted')) { + location.reload(); + }; + }); + // Enable editable grid on checkbox. $enableEg.find('input').removeAttr('disabled').change(function() { $this = $(this); if ($this.attr('checked')) { - enableEditableGrid(); + enableEditableGrid(allPostData); $this.attr('disabled', true); } $('#enable-eg').remove(); $('.spreadsheet-mode').show(); + $('#action-bar').find('a').each(function() { + $(this).css('display', 'none') + }); + $('#action-bar').append('Submit'); + $('#eg_submit').click( function() { + var confirm_str = "Are you sure you want to make the following changes?\n"; + jQuery.each(allPostData, function(i, data) { + confirm_str += data.oldValue + " -> " + data.newValue + "\n"; + }); + if (confirm(confirm_str)) { + $('.errors').each(function() { + $(this).remove(); + }); + var successIndex = []; + var success = true; + jQuery.each(allPostData, function(key, data) { + $.post(data.url, data.postData, function(resp) { + if (resp && resp.error) { + jQuery.each(resp.error, function(field, error) { + if (field == '__all__') { + $(data.row).after( + '