Commit 139e39eefdc9258719b07f906d88136e2e4c02f8

Authored by Marcel Kawski
1 parent 699a3d93

Correct splitting chunks feature

collector/storage/forms.py
... ... @@ -378,13 +378,12 @@ class ChunkMergeForm(ModelForm):
378 378 fields = ['target_chunk']
379 379  
380 380  
381   -class ChunkSplitForm(ModelForm):
382   -
383   - class Meta:
384   - model = Chunk
385   -
386   - fields = ['text']
387   -
388   - labels = {
389   - 'text': 'Tekst nowej sekcji'
390   - }
  381 +class ChunkSplitForm(Form):
  382 + text = CharField(required=True)
  383 +
  384 + def __init__(self, initial_text, *args, **kwargs):
  385 + super(ChunkSplitForm, self).__init__(*args, **kwargs)
  386 + self.fields['text'].initial = initial_text
  387 + self.fields['text'].widget = Textarea(attrs={'class': 'formset-field',
  388 + 'placeholder': 'Tekst sekcji',
  389 + 'rows': 5})
... ...
collector/storage/static/storage/css/document.css
... ... @@ -168,6 +168,15 @@ a.nav-button:hover {
168 168 color: #ff6600;
169 169 }
170 170  
  171 +i.remove-form-row {
  172 + color: red;
  173 + cursor: pointer;
  174 +}
  175 +
  176 +i.remove-form-row:hover {
  177 + color: #870000;
  178 +}
  179 +
171 180 .col-actions {
172 181 width: 5%;
173 182 }
... ... @@ -212,6 +221,14 @@ a.nav-button:hover {
212 221 width: 10%;
213 222 }
214 223  
  224 +.col-remove {
  225 + width: 3%;
  226 +}
  227 +
  228 +tr.item textarea {
  229 + width: 100%;
  230 +}
  231 +
215 232 #doc-list-table {
216 233 table-layout: fixed;
217 234 }
... ...
collector/storage/static/storage/js/formset.js
1 1 function updateElementIndex(el, prefix, ndx) {
2 2 var id_regex = new RegExp('(' + prefix + '-\\d+-)');
3 3 var replacement = prefix + '-' + ndx + '-';
4   - if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex,
5   - replacement));
  4 + if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
6 5 if (el.id) el.id = el.id.replace(id_regex, replacement);
7 6 if (el.name) el.name = el.name.replace(id_regex, replacement);
8 7 }
9 8  
10 9 function addForm(btn, prefix) {
11 10 var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
12   - if (formCount < 1000) {
13   - // Clone a form (without event handlers) from the first form
  11 + if (formCount < 3) {
14 12 var row = $(".item:last").clone(false).get(0);
15   -
16   - // Insert it after the last form
17 13 $(row).removeAttr('id').hide().insertAfter(".item:last").slideDown(300);
18   -
19   - // Remove the bits we don't want in the new row/form
20   - // e.g. error messages
21 14 $(".errorlist", row).remove();
22 15 $(row).children().removeClass("error");
23   -
24   - // Relabel or rename all the relevant bits
25 16 $(row).find('.formset-field').each(function () {
26 17 updateElementIndex(this, prefix, formCount);
27 18 $(this).val('');
28 19 $(this).removeAttr('value');
29 20 $(this).prop('checked', false);
30 21 });
31   -
32   - // Add an event handler for the delete item/form link
33 22 $(row).find(".delete").click(function () {
34 23 return deleteForm(this, prefix);
35 24 });
36   - // Update the total form count
37 25 $("#id_" + prefix + "-TOTAL_FORMS").val(formCount + 1);
38   -
39   - } // End if
  26 + }
40 27  
41 28 return false;
42 29 }
... ... @@ -45,11 +32,11 @@ function addForm(btn, prefix) {
45 32 function deleteForm(btn, prefix) {
46 33 var formCount = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
47 34 if (formCount > 1) {
48   - // Delete the item/form
49 35 var goto_id = $(btn).find('input').val();
50 36 if( goto_id ){
51 37 $.ajax({
52   - url: "/" + window.location.pathname.split("/")[1] + "/formset-data-delete/"+ goto_id +"/?next="+ window.location.pathname,
  38 + url: "/" + window.location.pathname.split("/")[1] + "/formset-data-delete/" + goto_id +
  39 + "/?next=" + window.location.pathname,
53 40 error: function () {
54 41 console.log("error");
55 42 },
... ... @@ -62,17 +49,15 @@ function deleteForm(btn, prefix) {
62 49 $(btn).parents('.item').remove();
63 50 }
64 51  
65   - var forms = $('.item'); // Get all the forms
66   - // Update the total number of forms (1 less than before)
  52 + var forms = $('.item');
67 53 $('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
68 54 var i = 0;
69   - // Go through the forms and set their indices, names and IDs
70 55 for (formCount = forms.length; i < formCount; i++) {
71 56 $(forms.get(i)).find('.formset-field').each(function () {
72 57 updateElementIndex(this, prefix, i);
73 58 });
74 59 }
75   - } // End if
  60 + }
76 61  
77 62 return false;
78 63 }
... ...
collector/storage/templates/storage/chunk-split.html
... ... @@ -24,29 +24,39 @@
24 24 </div>
25 25  
26 26 <div class="modal-body">
  27 +
  28 + <div class="alert alert-warning text-center" role="alert"><strong>Uwaga!</strong> Zamknięcie formularza nie spodowuje zapisania
  29 + zmian. W razie pomyłki lub nieumyślnego usunięcia sekcji zamknij to okno.</div>
  30 +
27 31 <form method="POST">
28 32 {% csrf_token %}
29 33 {{ form.as_p}}
  34 +
  35 + <table class="table">
30 36  
31   - {% for form in formset %}
32   - <div class="item">
33   - {% for field in form %}
34   - {% render_field field class="form-control" placeholder=field.label %}</td>
  37 + <tbody>
  38 + {% for form in formset %}
  39 + <tr class="item">
  40 + {% for field in form %}
  41 + <td class="col-field">
  42 + {{ field }}
  43 + </td>
  44 + {% endfor %}
  45 + <td class="col-remove">
  46 + <i class="remove-form-row material-icons" id="{{ formset.prefix }}" title="Usuń sekcję">clear</i>
  47 + </td>
  48 + </tr>
35 49 {% endfor %}
36   - <button type="button" class="btn btn-danger btn-sm remove-form-row"
37   - id="{{ formset.prefix }}">
38   - Usuń
39   - </button>
40   - <br><br>
41   - </div>
42   - {% endfor %}
43   -
44   - <button type="button" class="btn btn-sm btn-success add-form-row" id="{{ formset.prefix }}">
45   - Dodaj</button>
  50 + </tbody>
  51 +
  52 + </table>
46 53  
47 54 {{ formset.management_form }}
48 55  
49 56 <div class="modal-footer">
  57 + <button type="button" class="btn btn-sm btn-success add-form-row mr-auto" id="{{ formset.prefix }}">
  58 + Dodaj sekcję <i class="material-icons def-col-button">add</i>
  59 + </button>
50 60 <button type="submit" class="submit-btn btn btn-primary">{{ submit_btn_text }}</button>
51 61 </div>
52 62  
... ...
collector/storage/views.py
... ... @@ -14,10 +14,12 @@ from django.contrib.auth.decorators import login_required
14 14 from django.db.models.query import QuerySet
15 15 from django.db.models import Q
16 16 from django.template.loader import render_to_string
17   -from django.forms import modelformset_factory
  17 +from django.forms import modelformset_factory, formset_factory
  18 +from django.db import transaction, IntegrityError
18 19  
19 20 from keras import backend
20 21 from sys import maxsize
  22 +from functools import partial, wraps
21 23  
22 24 from .forms import ChunkForm, ParticipantForm, SubchunkForm, MetadataForm, DocDetailsForm, KeywordForm, DocSplitForm, \
23 25 ChunkMoveForm, SubDocDetailsForm, AuthorForm, ChunkMergeForm, ChunkSplitForm
... ... @@ -78,18 +80,37 @@ def swap_subdocs(direction, subdoc, subdoc_seq, temp_seq, max_seq, parent_doc):
78 80  
79 81 def split_chunk(request, pk):
80 82 context = {}
81   - ChunksFormset = modelformset_factory(Chunk, form=ChunkSplitForm)
82   - formset = ChunksFormset(request.POST or None, queryset=Chunk.objects.none(), prefix='chunks')
  83 + chunk = Chunk.objects.get(pk=pk)
  84 + ChunksFormset = formset_factory(wraps(ChunkSplitForm)(partial(ChunkSplitForm, initial_text=chunk.text)))
  85 + formset = ChunksFormset(request.POST or None, prefix='chunks')
83 86 if request.method == "POST":
84   - if formset.is_valid():
85   - for f in formset:
86   - # TODO
87   - chunk = f.save(commit=False)
88   - chunk.save()
89   - return redirect('annotation')
  87 + chunk_document_id = chunk.document.id
  88 + formset_len = len(formset)
  89 + if formset_len > 1 and formset.is_valid() and not request.is_ajax():
  90 + next_chunks = Chunk.objects.filter(document=chunk.document,
  91 + sequence__gt=chunk.sequence).order_by('-sequence')
  92 + for ch in next_chunks:
  93 + ch.sequence += formset_len - 1
  94 + ch.save()
  95 + old_chunk = Chunk.objects.create(text=formset[0].data['chunks-0-text'],
  96 + document=chunk.document,
  97 + sequence=chunk.sequence)
  98 + old_chunk.save()
  99 + for num, f in enumerate(formset[1:]):
  100 + ch = Chunk.objects.create(text=f.cleaned_data['text'],
  101 + document=chunk.document,
  102 + sequence=chunk.sequence + num + 1)
  103 + ch.save()
  104 + chunk.delete()
  105 + return HttpResponseRedirect('%s#chunk-%d' % (
  106 + reverse_lazy('annotation', kwargs={'doc_id': chunk_document_id}), old_chunk.pk))
  107 + else:
  108 + messages.error(request, 'Błąd: Nieprawidłowy podział sekcji')
  109 + return HttpResponseRedirect(reverse('annotation', kwargs={'doc_id': chunk_document_id}))
90 110 context['formset'] = formset
91 111 context['title'] = 'Dzielenie sekcji'
92 112 context['submit_btn_text'] = 'Podziel'
  113 + formset.data['chunks-TOTAL_FORMS'] = 0
93 114 return render(request, 'storage/chunk-split.html', context)
94 115  
95 116  
... ...