From d7783aad6402b643a5a36d0a5cf6b4cb4fe596f7 Mon Sep 17 00:00:00 2001
From: Robin Tissot <tissotrobin@gmail.com>
Date: Fri, 12 Mar 2021 11:48:49 +0100
Subject: [PATCH] functional goto modal.

---
 app/apps/api/views.py               | 18 +++++++++++++++
 front/css/escriptorium.css          |  4 ++++
 front/src/editor/api.js             |  4 +++-
 front/src/editor/store/document.js  |  5 ++++
 front/src/editor/store/parts.js     | 30 ++++++++++++++++++++----
 front/vue/components/Editor.vue     |  5 +---
 front/vue/components/ExtraInfo.vue  | 36 ++++++++++++++++++++++++++++-
 front/vue/components/TabContent.vue |  3 ---
 8 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/app/apps/api/views.py b/app/apps/api/views.py
index 19fc3765..23722ea8 100644
--- a/app/apps/api/views.py
+++ b/app/apps/api/views.py
@@ -4,7 +4,9 @@ import logging
 from django.conf import settings
 from django.core.exceptions import PermissionDenied
 from django.db.models import Prefetch
+from django.http import HttpResponseRedirect
 from django.shortcuts import get_object_or_404
+from django.urls import reverse
 
 from rest_framework.decorators import action
 from rest_framework.response import Response
@@ -193,6 +195,22 @@ class PartViewSet(DocumentPermissionMixin, ModelViewSet):
         else:  # list & create
             return PartSerializer
 
+    @action(detail=False, methods=['get'])
+    def byorder(self, request, document_pk=None):
+        try:
+            order = int(request.GET.get('order'))
+        except ValueError:
+            return Response({'error': 'invalid order.'})
+        if not order:
+            return Response({'error': 'pass order as an url parameter.'})
+        try:
+            part = self.get_queryset().get(order=order)
+        except DocumentPart.DoesNotExist:
+            return Response({'error': 'Out of bounds.'})
+        return HttpResponseRedirect(reverse('api:part-detail',
+                                            kwargs={'document_pk': self.kwargs.get('document_pk'),
+                                                    'pk': part.pk}))
+
     @action(detail=True, methods=['post'])
     def move(self, request, document_pk=None, pk=None):
         part = DocumentPart.objects.get(document=document_pk, pk=pk)
diff --git a/front/css/escriptorium.css b/front/css/escriptorium.css
index f6e86791..9070c273 100644
--- a/front/css/escriptorium.css
+++ b/front/css/escriptorium.css
@@ -386,6 +386,10 @@ form.inline-form {
     color: grey;
 }
 
+#gotoModal .modal-dialog {
+    max-width: 355px;
+}
+
 .col-sides {
     width: 30px;
     margin: 0 15px;
diff --git a/front/src/editor/api.js b/front/src/editor/api.js
index 2cf9820b..52851785 100644
--- a/front/src/editor/api.js
+++ b/front/src/editor/api.js
@@ -10,6 +10,8 @@ export const retrieveDocument = async document_id => (await axios.get(`/document
 
 export const retrieveDocumentPart = async (document_id, part_id) => (await axios.get(`/documents/${document_id}/parts/${part_id}/`))
 
+export const retrieveDocumentPartByOrder = async (document_id, order) => (await axios.get(`/documents/${document_id}/parts/byorder/?order=${order}`))
+
 export const retrievePage = async (document_id, part_id, transcription, page) => (await axios.get(`/documents/${document_id}/parts/${part_id}/transcriptions/?transcription=${transcription}&page=${page}`))
 
 export const createContent = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/transcriptions/`, data))
@@ -40,4 +42,4 @@ export const bulkCreateLineTranscriptions = async (document_id, part_id, data) =
 
 export const bulkUpdateLineTranscriptions = async (document_id, part_id, data) => (await axios.put(`/documents/${document_id}/parts/${part_id}/transcriptions/bulk_update/`, data))
 
-export const moveLines = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/lines/move/`, data))
\ No newline at end of file
+export const moveLines = async (document_id, part_id, data) => (await axios.post(`/documents/${document_id}/parts/${part_id}/lines/move/`, data))
diff --git a/front/src/editor/store/document.js b/front/src/editor/store/document.js
index 88bf2074..ee3ffe0a 100644
--- a/front/src/editor/store/document.js
+++ b/front/src/editor/store/document.js
@@ -4,6 +4,7 @@ import * as api from '../api'
 export const initialState = () => ({
     id: null,
     name: "",
+    partsCount: 0,
     defaultTextDirection: null,
     mainTextDirection: null,
     readDirection: null,
@@ -39,6 +40,9 @@ export const mutations = {
     setTypes (state, types) {
         state.types = types
     },
+    setPartsCount(state, count) {
+        state.partsCount = count
+    },
     setBlockShortcuts(state, block) {
         state.blockShortcuts = block
     },
@@ -56,6 +60,7 @@ export const actions = {
         let data = resp.data
         commit('transcriptions/set', data.transcriptions, {root: true})
         commit('setTypes', { 'regions': data.valid_block_types, 'lines': data.valid_line_types })
+        commit('setPartsCount', data.parts_count)
     },
 
     async togglePanel ({state, commit}, panel) {
diff --git a/front/src/editor/store/parts.js b/front/src/editor/store/parts.js
index ed1ce964..3d366ad3 100644
--- a/front/src/editor/store/parts.js
+++ b/front/src/editor/store/parts.js
@@ -31,12 +31,19 @@ export const mutations = {
 }
 
 export const actions = {
-    async fetchPart ({commit, dispatch, rootState}, pk) {
-        commit('setPartPk', pk)
+    async fetchPart ({commit, dispatch, rootState}, {pk, order}) {
         if (!rootState.transcriptions.all.length) {
             await dispatch('document/fetchDocument', rootState.document.id, {root: true})
         }
-        const resp = await api.retrieveDocumentPart(rootState.document.id, pk)
+        var resp
+        if (pk) {
+            commit('setPartPk', pk)
+            resp = await api.retrieveDocumentPart(rootState.document.id, pk)
+        } else {
+            resp = await api.retrieveDocumentPartByOrder(rootState.document.id, order)
+            commit('setPartPk', resp.data.pk)
+        }
+
         let data = resp.data
 
         data.lines.forEach(function(line) {
@@ -63,7 +70,20 @@ export const actions = {
         commit('regions/reset', {}, {root: true})
         commit('lines/reset', {}, {root: true})
         commit('reset')
-        await dispatch('fetchPart', pk)
+        await dispatch('fetchPart', {pk: pk})
+    },
+
+    async loadPartByOrder({state, commit, dispatch, rootState}, order) {
+        commit('regions/reset', {}, {root: true})
+        commit('lines/reset', {}, {root: true})
+        commit('reset')
+        try {
+            await dispatch('fetchPart', {order: order})
+            await dispatch('transcriptions/getCurrentContent', rootState.transcriptions.selectedTranscription, {root: true})
+            await dispatch('transcriptions/getComparisonContent', {}, {root: true})
+        } catch (err) {
+            console.log('couldnt fetch part data!', err)
+        }
     },
 
     async loadPart({state, commit, dispatch, rootState}, direction) {
@@ -73,7 +93,7 @@ export const actions = {
         commit('lines/reset', {}, {root: true})
         commit('reset')
         try {
-            await dispatch('fetchPart', part)
+            await dispatch('fetchPart', {pk: part})
             await dispatch('transcriptions/getCurrentContent', rootState.transcriptions.selectedTranscription, {root: true})
             await dispatch('transcriptions/getComparisonContent', {}, {root: true})
         } catch (err) {
diff --git a/front/vue/components/Editor.vue b/front/vue/components/Editor.vue
index 68a426eb..ca623312 100644
--- a/front/vue/components/Editor.vue
+++ b/front/vue/components/Editor.vue
@@ -4,7 +4,6 @@
             <div class="nav nav-tabs mb-3" id="nav-tab" role="tablist">
                 <slot></slot>
                 <extrainfo></extrainfo>
-                <gotoelement></gotoelement>
                 <transmanagement></transmanagement>
                 <extranav></extranav>
             </div>
@@ -16,7 +15,6 @@
 
 <script>
 import ExtraInfo from './ExtraInfo.vue';
-import GotoElement from './GotoElement.vue';
 import TranscriptionManagement from './TranscriptionManagement.vue';
 import ExtraNav from './ExtraNav.vue';
 import TabContent from './TabContent.vue';
@@ -71,7 +69,6 @@ export default {
 
     components: {
         'extrainfo': ExtraInfo,
-        'gotoelement': GotoElement,
         'transmanagement': TranscriptionManagement,
         'extranav': ExtraNav,
         'tabcontent': TabContent,
@@ -84,7 +81,7 @@ export default {
         this.$store.commit('document/setMainTextDirection', this.mainTextDirection);
         this.$store.commit('document/setReadDirection', this.readDirection);
         try {
-            await this.$store.dispatch('parts/fetchPart', this.partId);
+            await this.$store.dispatch('parts/fetchPart', {pk: this.partId});
             let tr = userProfile.get('initialTranscriptions')
                   && userProfile.get('initialTranscriptions')[this.$store.state.document.id]
                   || this.$store.state.transcriptions.all[0].pk;
diff --git a/front/vue/components/ExtraInfo.vue b/front/vue/components/ExtraInfo.vue
index 218f0ae6..6dc3d618 100644
--- a/front/vue/components/ExtraInfo.vue
+++ b/front/vue/components/ExtraInfo.vue
@@ -2,18 +2,52 @@
     <div>
         <div class="nav-div nav-item ml-2">
             <span v-if="$store.state.document.name" id="part-name">{{ $store.state.document.name }}</span>
-            <span id="part-title" v-if="$store.state.parts.loaded">{{ $store.state.parts.title }} - {{ $store.state.parts.filename }} - ({{ imageSize }})</span>
+            <span id="part-title" v-if="$store.state.parts.loaded" data-toggle="modal" data-target="#gotoModal" role="button">{{ $store.state.parts.title }} - {{ $store.state.parts.filename }} - ({{ imageSize }})</span>
             <span class="loading" v-if="!$store.state.parts.loaded">Loading&#8230;</span>
         </div>
+
+        <div id="gotoModal"
+             class="modal ui-draggable show"
+             tabindex="-1"
+             role="dialog">
+          <div class="modal-dialog modal-dialog-centered">
+            <div class="modal-content">
+              <div class="modal-body">
+                Element #
+                <input type="number"
+                       v-if="$store.state.parts.loaded"
+                       min="1"
+                       :max="$store.state.document.partsCount"
+                       width="100%"
+                       v-bind:value="$store.state.parts.order+1"
+                       @change.lazy="goTo"/>
+                / {{$store.state.document.partsCount}}
+              </div>
+            </div>
+          </div>
+        </div>
     </div>
 </template>
 
 <script>
 export default {
+    async created() {
+        document.addEventListener('keyup', async function(event) {
+            if (event.ctrlKey && event.keyCode == 36) { // Home
+                $('#gotoModal').modal('show');
+            }
+        });
+    },
     computed: {
         imageSize() {
             return this.$store.state.parts.image.size[0]+'x'+this.$store.state.parts.image.size[1];
         },
+    },
+    methods: {
+        async goTo(ev) {
+            await this.$store.dispatch('parts/loadPartByOrder', ev.target.value-1);
+            $('#gotoModal').modal('hide');
+        }
     }
 }
 </script>
diff --git a/front/vue/components/TabContent.vue b/front/vue/components/TabContent.vue
index e07e81a2..b51bd7eb 100644
--- a/front/vue/components/TabContent.vue
+++ b/front/vue/components/TabContent.vue
@@ -156,9 +156,6 @@ export default {
         resetZoom() {
             this.zoom.reset();
         },
-        async goTo(ev) {
-            await this.$store.dispatch('parts/loadPart', 'previous');
-        },
         async getPrevious(ev) {
             await this.$store.dispatch('parts/loadPart', 'previous');
         },
-- 
GitLab