diff --git a/app/apps/api/serializers.py b/app/apps/api/serializers.py index ed97f2b477a30f8a829186aca3f33b8ea56df20a..36122feb22fe940a8a51a1c8a4938094b19aea90 100644 --- a/app/apps/api/serializers.py +++ b/app/apps/api/serializers.py @@ -200,26 +200,39 @@ class LineSerializer(serializers.ModelSerializer): list_serializer_class = LineListSerializer -class LineMoveSerializer(serializers.ModelSerializer): - index = serializers.IntegerField() +class LineOrderListSerializer(serializers.ListSerializer): + def update(self, qs, validated_data): + # Maps for id->instance and id->data item. + line_mapping = {line.pk: line for line in qs} + data_mapping = {item['pk']: item for item in validated_data} - class Meta: - model = Line - fields = ('index',) + # we can only go down or up (not both) + first_ = qs[0] + down = first_.order < data_mapping[first_.pk]['order'] + lines = list(data_mapping.items()) + lines.sort(key=lambda l: l[1]['order']) + if down: + # reverse to avoid pushing up already moved lines + lines.reverse() - def __init__(self, *args, line=None, **kwargs): - self.line = line - super().__init__(*args, **kwargs) + for i, (line_id, data) in enumerate(lines): + line = line_mapping.get(line_id, None) + line.to(data['order']) - def move(self): - self.line.to(self.validated_data['index']) - self.line.save() + line.document_part.enforce_line_order() + # returns all new ordering for the whole page + data = self.child.__class__(line.document_part.lines.all(), many=True).data + return data class LineOrderSerializer(serializers.ModelSerializer): + pk = serializers.IntegerField() + order = serializers.IntegerField() + class Meta: model = Line fields = ('pk', 'order') + list_serializer_class = LineOrderListSerializer class DetailedLineSerializer(LineSerializer): diff --git a/app/apps/api/views.py b/app/apps/api/views.py index ce58fd437769070df4ce720fae9c2727caf21b66..366475d0075557c62dd3d386c1235c77d5861a6d 100644 --- a/app/apps/api/views.py +++ b/app/apps/api/views.py @@ -23,7 +23,6 @@ from api.serializers import (UserOnboardingSerializer, BlockTypeSerializer, LineTypeSerializer, DetailedLineSerializer, - LineMoveSerializer, LineOrderSerializer, TranscriptionSerializer, LineTranscriptionSerializer) @@ -252,33 +251,14 @@ class LineViewSet(ModelViewSet): @action(detail=False, methods=['post']) def move(self, request, document_pk=None, part_pk=None, pk=None): - lines = request.data.get("lines") - response = [] - errors = [] - - for line in lines: - l = get_object_or_404(Line, pk=line["pk"]) - serializer = LineMoveSerializer(line=l, data=line) - if serializer.is_valid(): - serializer.move() - response.append(serializer.data) - else: - errors.append(errors) - - if errors: - return Response(errors, - status=status.HTTP_400_BAD_REQUEST) - return Response(response) - - # return Response(status=200, data=response) - - # line = get_object_or_404(Line, pk=pk) - # serializer = LineMoveSerializer(line=line, data=request.data) - # if serializer.is_valid(): - # serializer.move() - # return Response({'status': 'moved'}) - # else: - # return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + data = request.data.get('lines') + qs = Line.objects.filter(pk__in=[l['pk'] for l in data]) + serializer = LineOrderSerializer(qs, data=data, many=True) + if serializer.is_valid(): + resp = serializer.save() + return Response(resp, status=200) + else: + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LargeResultsSetPagination(PageNumberPagination): diff --git a/app/apps/core/models.py b/app/apps/core/models.py index 9d53131c50c21516270b718c6eaa968e92518dce..831f4ef470f556427953d531166eeb88bebf57de 100644 --- a/app/apps/core/models.py +++ b/app/apps/core/models.py @@ -763,6 +763,15 @@ class DocumentPart(OrderedModel): return to_calc + def enforce_line_order(self): + # django-ordered-model doesn't care about unicity and linearity... + lines = self.lines.order_by('order', 'pk') + for i, line in enumerate(lines): + if line.order != i: + logger.debug('Enforcing line order %d : %d' % (line.pk, i)) + line.order = i + line.save() + def validate_polygon(value): if value is None: @@ -829,7 +838,7 @@ class Line(OrderedModel): # Versioned, script = models.CharField(max_length=8, null=True, blank=True) # choices ?? # text direction order_with_respect_to = 'document_part' - version_ignore_fields = ('document_part', 'order') + # version_ignore_fields = ('document_part', 'order') typology = models.ForeignKey(LineType, null=True, blank=True, on_delete=models.SET_NULL) diff --git a/app/apps/core/static/js/edit/components/diplo_line.js b/app/apps/core/static/js/edit/components/diplo_line.js index 8fb919733abe7dd004875c20118b46ec0df8a69d..0a67afdafc8320a62e97b7709e0f92e1725165f6 100644 --- a/app/apps/core/static/js/edit/components/diplo_line.js +++ b/app/apps/core/static/js/edit/components/diplo_line.js @@ -23,17 +23,18 @@ var diploLine = LineBase.extend({ this.getEl().remove(); }, watch: { - 'line.order': function(n,o) { - // make sure it's at the right place, - // in case it was just created or the ordering got recalculated - let index = Array.from(this.$el.parentNode.children).indexOf(this.$el); - if (index != this.line.order) { - this.$el.parentNode.insertBefore( - this.$el, - this.$el.parentNode.children[this.line.order]); - this.setElContent(this.line.currentTrans.content); - } - }, + /* 'line.order': function(n,o) { + * // make sure it's at the right place, + * // in case it was just created or the ordering got recalculated + * let index = Array.from(this.$el.parentNode.children).indexOf(this.$el); + * console.log(index, this.line.order); + * if (index != this.line.order) { + * this.$el.parentNode.insertBefore( + * this.$el, + * this.$el.parentNode.children[this.line.order]); + * this.setElContent(this.line.currentTrans.content); + * } + * }, */ 'line.currentTrans': function(n, o) { if (n!=undefined && n.content) { this.setElContent(n.content); diff --git a/app/apps/core/static/js/edit/components/diplo_panel.js b/app/apps/core/static/js/edit/components/diplo_panel.js index 56c8e6ec22ab7b45dfcb40a5e42b29c340fad43f..fa8ba33fe6e87f474fbe61d67cbf5404db724df8 100644 --- a/app/apps/core/static/js/edit/components/diplo_panel.js +++ b/app/apps/core/static/js/edit/components/diplo_panel.js @@ -25,7 +25,7 @@ var DiploPanel = BasePanel.extend({ selectedClass: "selected", animation: 150, onEnd: function(evt) { - vm.onDragginEnd(evt); + vm.onDraggingEnd(evt); } }); }.bind(this)); @@ -97,21 +97,23 @@ var DiploPanel = BasePanel.extend({ this.constrainLineNumber(); this.save(); }, - onDragginEnd(ev) { + onDraggingEnd(ev) { /* Finish dragging lines, save new positions */ - if(ev.newIndicies.length == 0 && ev.newIndex != ev.oldIndex){ + if(ev.newIndicies.length == 0 && ev.newIndex != ev.oldIndex) { + let diploLine = this.$children.find(dl=>dl.line.order==ev.oldIndex); this.movedLines.push({ - "pk": this.$children[ev.oldIndex].line.pk, - "index": ev.newIndex + "pk": diploLine.line.pk, + "order": ev.newIndex }); } else { - for(let i=0; i< ev.newIndicies.length; i++){ - // TODO: doesn't appear to work?! + for(let i=0; i< ev.newIndicies.length; i++) { + + let diploLine = this.$children.find(dl=>dl.line.order==ev.oldIndicies[i].index); this.movedLines.push({ - "pk": this.$children[ev.oldIndicies[i].index].line.pk, - "index": ev.newIndicies[i].index + "pk": diploLine.line.pk, + "order": ev.newIndicies[i].index }); } } @@ -119,7 +121,7 @@ var DiploPanel = BasePanel.extend({ }, moveLines() { if(this.movedLines.length != 0){ - this.$parent.$emit('line:move', this.movedLines, function () { + this.$parent.$emit('move:line', this.movedLines, function () { this.movedLines = []; }.bind(this)); } @@ -213,7 +215,8 @@ var DiploPanel = BasePanel.extend({ let target = ev.target.nodeType==Node.TEXT_NODE?ev.target.parentNode:ev.target; let index = Array.prototype.indexOf.call(target.parentNode.children, target); if (index > -1 && index < this.$children.length) { - this.$children[index].showOverlay(); + let diploLine = this.$children.find(dl=>dl.line.order==index); + if (diploLine) diploLine.showOverlay(); } else { this.hideOverlay(); } @@ -248,8 +251,9 @@ var DiploPanel = BasePanel.extend({ */ for(let i=0; i<this.$children.length; i++) { let currentLine = this.$children[i]; - if(currentLine.line.currentTrans.content != currentLine.getEl().textContent){ - currentLine.line.currentTrans.content = currentLine.getEl().textContent; + let content = currentLine.getEl().textContent; + if(currentLine.line.currentTrans.content != content){ + currentLine.line.currentTrans.content = content; if(currentLine.line.currentTrans.pk) { this.addToUpdatedLines(currentLine.line.currentTrans); } else { diff --git a/app/apps/core/static/js/edit/main.js b/app/apps/core/static/js/edit/main.js index 9fdc0c41263aeb3d700278c3dd5239addc23573c..441e63c1f56a441a79d9ff987e1e754354e3fac0 100644 --- a/app/apps/core/static/js/edit/main.js +++ b/app/apps/core/static/js/edit/main.js @@ -128,9 +128,10 @@ var partVM = new Vue({ this.part.bulkUpdateLineTranscriptions(lines, cb); }.bind(this)); - this.$on('line:move', function(movedLines, cb) { + this.$on('move:line', function(movedLines, cb) { this.part.move(movedLines, cb); }.bind(this)); + document.addEventListener('keydown', function(event) { if (this.blockShortcuts) return; if (event.keyCode == 33 || // page up diff --git a/app/apps/core/static/js/edit/store/part.js b/app/apps/core/static/js/edit/store/part.js index 6b112e437b131d0e5cc7955efdeb598b86edeb29..f87f83bf401567c0996576228d2a98e95e35d2e8 100644 --- a/app/apps/core/static/js/edit/store/part.js +++ b/app/apps/core/static/js/edit/store/part.js @@ -453,13 +453,23 @@ const partStore = { console.log('couldnt update line', error) }); }, - move(movedLines,callback){ + move(movedLines, callback){ let uri = this.getApiPart()+ 'lines/move/'; this.push(uri,{"lines": movedLines},method="post") .then((response) =>response.json()) .then(function (data) { + for (let i=0; i<data.length; i++) { + let lineData = data[i]; + let line = this.lines.find(function(l) { + return l.pk==lineData.pk; + }); + if (line) { + if (line.order != lineData.order) console.log('change', line.pk, line.order, lineData.order); + line.order = lineData.order; + } + } callback(); - }).catch(function(error) { + }.bind(this)).catch(function(error) { console.log('couldnt recalculate order of line', error) }); },