@konfuzio/document-validation-ui 0.1.4 → 0.1.5-automatic-document-splitting

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/css/app.css +1 -1
  2. package/dist/index.html +1 -1
  3. package/dist/js/app.js +1 -1
  4. package/dist/js/app.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/assets/images/MagicWandIcon.vue +16 -0
  7. package/src/assets/images/ServerImage.vue +3 -0
  8. package/src/assets/images/SplitZigZag.vue +47 -14
  9. package/src/assets/images/StarIcon.vue +16 -0
  10. package/src/assets/scss/document_category.scss +0 -1
  11. package/src/assets/scss/document_dashboard.scss +6 -0
  12. package/src/assets/scss/document_edit.scss +135 -46
  13. package/src/assets/scss/splitting_confirmation_modal.scss +41 -0
  14. package/src/assets/scss/variables.scss +63 -1
  15. package/src/components/App.vue +11 -1
  16. package/src/components/DocumentAnnotations/ActionButtons.vue +7 -0
  17. package/src/components/DocumentAnnotations/AnnotationContent.vue +3 -0
  18. package/src/components/DocumentAnnotations/AnnotationRow.vue +3 -0
  19. package/src/components/DocumentAnnotations/CategorizeModal.vue +24 -4
  20. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +11 -3
  21. package/src/components/DocumentAnnotations/DocumentLabel.vue +2 -0
  22. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +6 -1
  23. package/src/components/DocumentCategory.vue +39 -33
  24. package/src/components/DocumentDashboard.vue +39 -49
  25. package/src/components/DocumentEdit/DocumentEdit.vue +207 -69
  26. package/src/components/DocumentEdit/EditConfirmationModal.vue +54 -0
  27. package/src/components/DocumentEdit/EditPages.vue +30 -18
  28. package/src/components/DocumentEdit/EditSidebar.vue +95 -45
  29. package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
  30. package/src/components/DocumentEdit/SplitInfoBar.vue +19 -0
  31. package/src/components/DocumentEdit/SplitOverview.vue +6 -5
  32. package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +3 -4
  33. package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
  34. package/src/components/DocumentModals/SplittingSuggestionsModal.vue +121 -0
  35. package/src/components/DocumentPage/DocumentPage.vue +9 -3
  36. package/src/components/DocumentPage/DummyPage.vue +9 -7
  37. package/src/components/DocumentPage/ScrollingDocument.vue +8 -3
  38. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +45 -8
  39. package/src/components/DocumentTopBar/DocumentName.vue +1 -0
  40. package/src/components/DocumentTopBar/DocumentTopBar.vue +2 -6
  41. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +6 -20
  42. package/src/components/index.js +1 -0
  43. package/src/locales/de.json +15 -2
  44. package/src/locales/en.json +15 -1
  45. package/src/locales/es.json +14 -1
  46. package/src/store/display.js +8 -0
  47. package/src/store/document.js +83 -37
  48. package/src/store/edit.js +66 -48
  49. package/src/store/project.js +14 -14
@@ -1,75 +1,105 @@
1
1
  <template>
2
2
  <div class="edit-sidebar">
3
- <div class="sidebar-header">
4
- <h3 class="sidebar-title">
5
- {{ $t("edit_document") }}
6
- </h3>
7
- <p class="description">
8
- {{ $t("edit_early_access") }}
9
- </p>
10
- <p class="description">
11
- {{ $t("select_pages") }}
12
- </p>
13
- </div>
14
-
15
3
  <div class="buttons-container">
16
- <div class="rotate-selected rotate">
4
+ <div class="rotate-selected edit-buttons">
5
+ <SidebarButtons
6
+ :show-rotate-button="true"
7
+ :button-disabled="buttonDisabled"
8
+ :button-text="$t('rotate_selected')"
9
+ :icon="'arrow-rotate-left'"
10
+ @rotate="rotateLeft"
11
+ />
12
+
13
+ <SidebarButtons
14
+ :show-rotate-button="true"
15
+ :button-disabled="buttonDisabled"
16
+ :button-text="$t('rotate_selected')"
17
+ :icon="'arrow-rotate-right'"
18
+ @rotate="rotateRight"
19
+ />
20
+
17
21
  <p :class="['pages-selected', buttonDisabled && 'disabled']">
18
22
  {{ selectedPages.length }} {{ $t("selected") }}
19
23
  </p>
20
- <b-button
21
- class="rotate-button primary-button"
22
- :disabled="buttonDisabled"
23
- @click="rotateLeft"
24
- >
25
- <div class="button-content">
26
- <b-icon icon="arrow-rotate-left" class="is-small" />
27
- <span class="button-text">{{ $t("rotate_selected") }}</span>
28
- </div>
29
- </b-button>
30
- <b-button
31
- class="rotate-button primary-button"
32
- :disabled="buttonDisabled"
33
- @click="rotateRight"
34
- >
35
- <div class="button-content">
36
- <b-icon icon="arrow-rotate-right" class="is-small" />
37
- <span class="button-text">{{ $t("rotate_selected") }}</span>
38
- </div>
39
- </b-button>
40
24
  </div>
41
25
 
42
- <div class="rotate-all rotate">
43
- <b-button class="rotate-button primary-button" @click="rotateAllLeft">
44
- <b-icon icon="arrow-rotate-left" class="is-small" />
45
- <span class="button-text">{{ $t("rotate_all") }}</span>
46
- </b-button>
47
- <b-button class="rotate-button primary-button" @click="rotateAllRight">
48
- <b-icon icon="arrow-rotate-right" class="is-small" />
49
- <span class="button-text">{{ $t("rotate_all") }}</span>
50
- </b-button>
26
+ <div class="rotate-all edit-buttons">
27
+ <SidebarButtons
28
+ :show-rotate-button="true"
29
+ :button-disabled="false"
30
+ :button-text="$t('rotate_all')"
31
+ :icon="'arrow-rotate-left'"
32
+ @rotate="rotateAllLeft"
33
+ />
34
+
35
+ <SidebarButtons
36
+ :show-rotate-button="true"
37
+ :button-disabled="false"
38
+ :button-text="$t('rotate_all')"
39
+ :icon="'arrow-rotate-right'"
40
+ @rotate="rotateAllRight"
41
+ />
51
42
  </div>
52
43
  </div>
44
+ <div class="split smart-split">
45
+ <b-tooltip
46
+ multilined
47
+ :active="!documentHasProposedSplit(selectedDocument)"
48
+ position="is-bottom"
49
+ class="bottom-aligned"
50
+ :label="tooltipInfo"
51
+ >
52
+ <b-field>
53
+ <b-switch
54
+ :value="true"
55
+ size="is-small"
56
+ v-model="switchStatus"
57
+ :disabled="!documentHasProposedSplit(selectedDocument)"
58
+ >
59
+ <span class="switch-text">{{ $t("smart_split") }}</span>
60
+ <span
61
+ v-if="documentHasProposedSplit(selectedDocument)"
62
+ class="new-badge"
63
+ >{{ newText }}</span
64
+ >
65
+ </b-switch>
66
+ </b-field>
67
+ </b-tooltip>
68
+ </div>
53
69
  </div>
54
70
  </template>
55
71
 
56
72
  <script>
73
+ import { mapState, mapGetters } from "vuex";
74
+ import { nextTick } from "vue";
75
+ import SidebarButtons from "./SidebarButtons";
76
+
57
77
  /**
58
78
  * This component renders buttons to rotate single pages or all pages
59
79
  * in edit mode
60
80
  * */
61
-
62
- import { mapState } from "vuex";
63
-
64
81
  export default {
65
82
  name: "EditSidebar",
83
+ components: {
84
+ SidebarButtons,
85
+ },
66
86
  data() {
67
87
  return {
68
88
  buttonDisabled: true,
89
+ tooltipInfo: null,
90
+ newText: this.$t("new"),
91
+ switchStatus: true,
69
92
  };
70
93
  },
94
+ props: {
95
+ splitSuggestionsEnabled: {
96
+ type: Boolean,
97
+ },
98
+ },
71
99
  computed: {
72
100
  ...mapState("edit", ["selectedPages"]),
101
+ ...mapState("document", ["splittingSuggestions", "selectedDocument"]),
102
+ ...mapGetters("document", ["documentHasProposedSplit"]),
73
103
  },
74
104
  watch: {
75
105
  selectedPages(newValue) {
@@ -79,6 +109,26 @@ export default {
79
109
  this.buttonDisabled = true;
80
110
  }
81
111
  },
112
+ switchStatus(newValue) {
113
+ if (this.splittingSuggestions && this.splittingSuggestions.length > 0)
114
+ this.$emit("handle-splitting-suggestions", newValue);
115
+ },
116
+ splitSuggestionsEnabled(newValue) {
117
+ if (!newValue) {
118
+ this.switchStatus = false;
119
+ }
120
+ },
121
+ },
122
+ mounted() {
123
+ this.tooltipInfo = this.$t("no_splitting_suggestions");
124
+
125
+ nextTick(() => {
126
+ if (this.newText) {
127
+ this.newText = this.$t("new").toUpperCase();
128
+ }
129
+
130
+ this.switchStatus = this.splitSuggestionsEnabled;
131
+ });
82
132
  },
83
133
  methods: {
84
134
  rotateLeft() {
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div class="sidebar-buttons">
3
+ <!-- Rotate buttons -->
4
+ <div v-if="showRotateButton" class="rotate-button-container">
5
+ <b-button
6
+ class="rotate-button edit-mode-btn primary-button"
7
+ :disabled="buttonDisabled"
8
+ @click="rotateButton"
9
+ >
10
+ <div class="button-content">
11
+ <b-icon :icon="icon" class="is-small" />
12
+ <span class="button-text">{{ buttonText }}</span>
13
+ </div>
14
+ </b-button>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script>
20
+ export default {
21
+ name: "SidebarButtons",
22
+ props: {
23
+ showRotateButton: {
24
+ type: Boolean,
25
+ default: false,
26
+ },
27
+ buttonDisabled: {
28
+ type: Boolean,
29
+ default: true,
30
+ },
31
+ buttonText: {
32
+ type: String,
33
+ default: null,
34
+ },
35
+ icon: {
36
+ type: String,
37
+ default: null,
38
+ },
39
+ tooltipInfo: {
40
+ type: String,
41
+ default: null,
42
+ },
43
+ },
44
+
45
+ methods: {
46
+ rotateButton() {
47
+ this.$emit("rotate");
48
+ },
49
+ },
50
+ };
51
+ </script>
52
+
53
+ <style scoped lang="scss" src="../../assets/scss/document_edit.scss"></style>
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <div class="split-info-bar">
3
+ <StarIcon />
4
+ <span> {{ $t("smart_split_suggestions") }}</span>
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+ import StarIcon from "../../assets/images/StarIcon";
10
+
11
+ export default {
12
+ name: "SplitInfoBar",
13
+ components: {
14
+ StarIcon,
15
+ },
16
+ };
17
+ </script>
18
+
19
+ <style scoped lang="scss" src="../../assets/scss/document_edit.scss"></style>
@@ -97,9 +97,11 @@ export default {
97
97
  props: {
98
98
  fileName: {
99
99
  type: String,
100
+ default: "",
100
101
  },
101
102
  fileExtension: {
102
103
  type: String,
104
+ default: "",
103
105
  },
104
106
  },
105
107
  data() {
@@ -110,7 +112,7 @@ export default {
110
112
  },
111
113
  computed: {
112
114
  ...mapState("document", ["selectedDocument", "pages"]),
113
- ...mapState("edit", ["updatedDocument", "documentPagesListForEditMode"]),
115
+ ...mapState("edit", ["updatedDocument", "pagesForPostprocess"]),
114
116
  },
115
117
  methods: {
116
118
  handleBackButton() {
@@ -160,11 +162,11 @@ export default {
160
162
  return name.split(".").slice(0, -1).join(".");
161
163
  },
162
164
  getImageUrl(page) {
163
- if (!this.documentPagesListForEditMode || !this.pages || !page) return;
165
+ if (!this.pagesForPostprocess || !this.pages || !page) return;
164
166
 
165
167
  // returns the first thumbnail in the pages array
166
168
  // for each new document
167
- const image = this.documentPagesListForEditMode.find(
169
+ const image = this.pagesForPostprocess.find(
168
170
  (p) => p.number === page.pages[0].number
169
171
  );
170
172
 
@@ -172,8 +174,7 @@ export default {
172
174
  },
173
175
  getRotation(pageId) {
174
176
  // rotate page
175
- return this.documentPagesListForEditMode?.find((p) => p.id === pageId)
176
- ?.angle;
177
+ return this.pagesForPostprocess?.find((p) => p.id === pageId)?.angle;
177
178
  },
178
179
  },
179
180
  };
@@ -29,11 +29,10 @@
29
29
  </template>
30
30
 
31
31
  <script>
32
- import { mapState } from "vuex";
33
- import ErrorIcon from "../assets/images/ErrorIcon";
32
+ import ErrorIcon from "../../assets/images/ErrorIcon";
34
33
 
35
34
  export default {
36
- name: "DocumentError",
35
+ name: "DocumentErrorModal",
37
36
  components: {
38
37
  ErrorIcon,
39
38
  },
@@ -54,4 +53,4 @@ export default {
54
53
  };
55
54
  </script>
56
55
 
57
- <style scoped lang="scss" src="../assets/scss/document_error.scss"></style>
56
+ <style scoped lang="scss" src="../../assets/scss/document_error.scss"></style>
@@ -24,7 +24,7 @@
24
24
  </template>
25
25
 
26
26
  <script>
27
- import Illustration from "../assets/images/NotOptimizedIllustration";
27
+ import Illustration from "../../assets/images/NotOptimizedIllustration";
28
28
 
29
29
  export default {
30
30
  name: "NotOptimizedViewportModal",
@@ -47,5 +47,5 @@ export default {
47
47
  <style
48
48
  scoped
49
49
  lang="scss"
50
- src="../assets/scss/document_viewport_modal.scss"
50
+ src="../../assets/scss/document_viewport_modal.scss"
51
51
  ></style>
@@ -0,0 +1,121 @@
1
+ <template>
2
+ <section ref="splittingModal" class="splitting-confirmation-modal">
3
+ <b-modal
4
+ v-model="isModalActive"
5
+ class="modal-400"
6
+ :width="500"
7
+ :can-cancel="[]"
8
+ >
9
+ <section class="modal-card-body split-modal">
10
+ <div class="header">
11
+ <StarIcon />
12
+ <p class="modal-title">
13
+ {{
14
+ splittingSuggestions && splittingSuggestions.length > 0
15
+ ? $t("split_modal_title")
16
+ : $t("prepare_document")
17
+ }}
18
+ </p>
19
+ </div>
20
+ <div ref="bodyText" class="content"></div>
21
+ </section>
22
+ <footer class="modal-card-foot">
23
+ <b-button @click="closeModal">
24
+ {{ $t("do_it_later") }}
25
+ </b-button>
26
+ <b-button type="is-primary" @click="handleReviewNow">
27
+ {{ $t("review_now") }}
28
+ <span class="recommended">{{ recommended }}</span>
29
+ </b-button>
30
+ </footer>
31
+ </b-modal>
32
+ </section>
33
+ </template>
34
+
35
+ <script>
36
+ import { nextTick } from "vue";
37
+ import { mapGetters, mapState } from "vuex";
38
+ import StarIcon from "../../assets/images/StarIcon";
39
+
40
+ /**
41
+ * This component shows a modal to inform the user about auto-splitting suggestions
42
+ */
43
+ export default {
44
+ name: "SplittingSuggestionsModal",
45
+ components: {
46
+ StarIcon,
47
+ },
48
+ data() {
49
+ return {
50
+ isModalActive: false,
51
+ recommended: this.$t("recommended"),
52
+ };
53
+ },
54
+ computed: {
55
+ ...mapState("document", ["splittingSuggestions", "selectedDocument"]),
56
+ ...mapGetters("document", ["waitingForSplittingConfirmation"]),
57
+ },
58
+ watch: {
59
+ splittingSuggestions(newValue) {
60
+ if (newValue) {
61
+ this.isModalActive = true;
62
+ }
63
+ },
64
+ isModalActive(newValue) {
65
+ if (newValue) {
66
+ this.$nextTick(() => {
67
+ if (
68
+ this.splittingSuggestions &&
69
+ this.splittingSuggestions.length > 0
70
+ ) {
71
+ this.$refs.bodyText.innerHTML = this.$t("split_modal_body", {
72
+ number_of_split_documents: this.splittingSuggestions.length,
73
+ });
74
+ } else {
75
+ this.$refs.bodyText.innerHTML = this.$t(
76
+ "split_modal_no_suggestions"
77
+ );
78
+ }
79
+ });
80
+ }
81
+ },
82
+ },
83
+ mounted() {
84
+ if (this.splittingSuggestions) {
85
+ this.isModalActive = true;
86
+ }
87
+
88
+ nextTick(() => {
89
+ if (this.recommended) {
90
+ this.recommended = this.recommended.toUpperCase();
91
+ }
92
+ });
93
+ },
94
+ methods: {
95
+ closeModal() {
96
+ const updatedDocument = [
97
+ {
98
+ name: this.selectedDocument.data_file_name,
99
+ category: this.selectedDocument.category,
100
+ pages: this.selectedDocument.pages,
101
+ },
102
+ ];
103
+
104
+ this.$store.dispatch("edit/editDocument", updatedDocument);
105
+
106
+ this.$store.dispatch("display/setCategorizeModalIsActive", false);
107
+ this.isModalActive = false;
108
+ },
109
+ handleReviewNow() {
110
+ this.$store.dispatch("edit/enableEditMode");
111
+ this.isModalActive = false;
112
+ },
113
+ },
114
+ };
115
+ </script>
116
+
117
+ <style
118
+ scoped
119
+ lang="scss"
120
+ src="../../assets/scss/splitting_confirmation_modal.scss"
121
+ ></style>
@@ -4,6 +4,7 @@
4
4
  :class="[
5
5
  'pdf-page-container',
6
6
  (categorizeModalIsActive || editMode || publicView) && 'default-cursor',
7
+ page.number === currentPage && 'current-page',
7
8
  ]"
8
9
  >
9
10
  <NewAnnotation
@@ -150,6 +151,8 @@ export default {
150
151
  },
151
152
 
152
153
  computed: {
154
+ ...mapState("display", ["currentPage"]),
155
+
153
156
  showFocusedAnnotation() {
154
157
  return (
155
158
  this.documentAnnotationSelected &&
@@ -242,7 +245,11 @@ export default {
242
245
  "selectionFromBbox",
243
246
  "spanSelection",
244
247
  ]),
245
- ...mapState("display", ["scale", "optimalScale"]),
248
+ ...mapState("display", [
249
+ "scale",
250
+ "optimalScale",
251
+ "categorizeModalIsActive",
252
+ ]),
246
253
  ...mapState("document", [
247
254
  "documentAnnotationSelected",
248
255
  "recalculatingAnnotations",
@@ -251,7 +258,6 @@ export default {
251
258
  "selectedDocument",
252
259
  "publicView",
253
260
  "selectedEntities",
254
- "categorizeModalIsActive",
255
261
  ]),
256
262
  ...mapState("edit", ["editMode"]),
257
263
  ...mapGetters("display", ["visiblePageRange", "bboxToRect"]),
@@ -452,7 +458,7 @@ export default {
452
458
  */
453
459
  entityRect(entity) {
454
460
  let entityIsSelected = false;
455
- if (this.newAnnotation) {
461
+ if (this.newAnnotation && this.newAnnotation.length > 0) {
456
462
  entityIsSelected = this.newAnnotation.find((selectedEntity) => {
457
463
  return (
458
464
  selectedEntity.entity.original.offset_string ===
@@ -20,18 +20,20 @@ import { PIXEL_RATIO } from "../../constants";
20
20
  export default {
21
21
  props: {
22
22
  width: {
23
- default: 0
23
+ default: 0,
24
+ type: Number,
24
25
  },
25
26
  height: {
26
- default: 0
27
- }
27
+ default: 0,
28
+ type: Number,
29
+ },
28
30
  },
29
31
  computed: {
30
32
  ...mapState("display", ["scale"]),
31
33
  actualSizeViewport() {
32
34
  return {
33
35
  width: this.width * this.scale,
34
- height: this.height * this.scale
36
+ height: this.height * this.scale,
35
37
  };
36
38
  },
37
39
 
@@ -39,7 +41,7 @@ export default {
39
41
  const { width: actualSizeWidth, height: actualSizeHeight } =
40
42
  this.actualSizeViewport;
41
43
  const [pixelWidth, pixelHeight] = [actualSizeWidth, actualSizeHeight].map(
42
- dim => Math.ceil(dim / PIXEL_RATIO)
44
+ (dim) => Math.ceil(dim / PIXEL_RATIO)
43
45
  );
44
46
  return { width: pixelWidth, height: pixelHeight };
45
47
  },
@@ -47,7 +49,7 @@ export default {
47
49
  canvasStyle() {
48
50
  const { width, height } = this.scaledViewport;
49
51
  return `width: ${width}px; height: ${height}px; margin: 0 auto`;
50
- }
51
- }
52
+ },
53
+ },
52
54
  };
53
55
  </script>
@@ -11,7 +11,7 @@
11
11
  "
12
12
  >
13
13
  <ScrollingPage
14
- v-for="page in editMode ? documentPagesListForEditMode : pages"
14
+ v-for="page in editMode ? pagesForPostprocess : pages"
15
15
  :key="page.number"
16
16
  :page="page"
17
17
  :client-height="clientHeight"
@@ -58,7 +58,7 @@ export default {
58
58
  "selectedDocument",
59
59
  "loading",
60
60
  ]),
61
- ...mapState("edit", ["editMode", "documentPagesListForEditMode"]),
61
+ ...mapState("edit", ["editMode", "pagesForPostprocess"]),
62
62
  ...mapState("display", ["scale", "documentActionBar"]),
63
63
 
64
64
  pages() {
@@ -69,7 +69,12 @@ export default {
69
69
  }
70
70
  },
71
71
  showToolbar() {
72
- return this.pages.length > 0 && this.scale && !this.documentActionBar;
72
+ return (
73
+ !this.loading &&
74
+ this.pages.length > 0 &&
75
+ this.scale &&
76
+ !this.documentActionBar
77
+ );
73
78
  },
74
79
  showActionBar() {
75
80
  return this.documentActionBar !== null;
@@ -1,12 +1,13 @@
1
1
  <template>
2
- <div class="document-pages">
2
+ <div ref="documentThumbnails" class="document-pages">
3
3
  <div v-if="selectedDocument">
4
4
  <div
5
5
  v-for="page in selectedDocument.pages"
6
+ ref="docPage"
6
7
  :key="page.id"
7
8
  :class="[
8
9
  'document-thumbnail',
9
- currentPage == page.number && 'selected'
10
+ currentPage == page.number && 'selected',
10
11
  ]"
11
12
  @click="changePage(page.number)"
12
13
  >
@@ -16,7 +17,7 @@
16
17
  v-if="!loading && !recalculatingAnnotations"
17
18
  :class="[
18
19
  'img-thumbnail',
19
- currentPage == page.number && 'selected'
20
+ currentPage == page.number && 'selected',
20
21
  ]"
21
22
  :width="'40px'"
22
23
  :image-url="`${page.thumbnail_url}?${selectedDocument.downloaded_at}`"
@@ -57,19 +58,44 @@ export default {
57
58
  name: "DocumentThumbnails",
58
59
  components: {
59
60
  ServerImage,
60
- LoadingThumbnail
61
+ LoadingThumbnail,
62
+ },
63
+ data() {
64
+ return {
65
+ thumbnailClicked: false,
66
+ previousScrollPosition: 0,
67
+ };
61
68
  },
62
69
  computed: {
63
70
  ...mapState("document", [
64
71
  "selectedDocument",
65
72
  "recalculatingAnnotations",
66
- "loading"
73
+ "loading",
67
74
  ]),
68
- ...mapState("display", ["currentPage"])
75
+ ...mapState("display", ["currentPage"]),
76
+ },
77
+ watch: {
78
+ currentPage(newPage) {
79
+ if (newPage && !this.thumbnailClicked) {
80
+ this.scrollToThumbnail();
81
+ }
82
+ },
69
83
  },
84
+ mounted() {
85
+ const scrollingPage = document.querySelector(".scrolling-document");
86
+
87
+ if (scrollingPage) {
88
+ scrollingPage.addEventListener("scroll", () => {
89
+ this.scrollToThumbnail();
90
+ });
91
+ }
92
+ },
93
+
70
94
  methods: {
71
95
  /* Change page if not the currently open and not in modal */
72
96
  changePage(pageNumber) {
97
+ this.thumbnailClicked = true;
98
+
73
99
  if (
74
100
  !this.loading &&
75
101
  !this.recalculatingAnnotations &&
@@ -80,8 +106,19 @@ export default {
80
106
  parseInt(pageNumber, 10)
81
107
  );
82
108
  }
83
- }
84
- }
109
+ },
110
+
111
+ scrollToThumbnail() {
112
+ // select only the active thumbnail
113
+ const selectedPage = this.$refs.docPage.filter((image) =>
114
+ image.className.includes("selected")
115
+ );
116
+
117
+ if (selectedPage && selectedPage[0]) {
118
+ selectedPage[0].scrollIntoView();
119
+ }
120
+ },
121
+ },
85
122
  };
86
123
  </script>
87
124
 
@@ -69,6 +69,7 @@ export default {
69
69
  props: {
70
70
  dataFileName: {
71
71
  type: String,
72
+ default: "",
72
73
  },
73
74
  },
74
75
  data() {