@konfuzio/document-validation-ui 0.1.5 → 0.1.6-pre-release-1

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 (53) 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/NotFoundIcon.vue +16 -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_annotations.scss +9 -59
  11. package/src/assets/scss/document_category.scss +0 -1
  12. package/src/assets/scss/document_dashboard.scss +6 -0
  13. package/src/assets/scss/document_edit.scss +90 -46
  14. package/src/assets/scss/main.scss +689 -7
  15. package/src/assets/scss/splitting_confirmation_modal.scss +41 -0
  16. package/src/assets/scss/variables.scss +0 -657
  17. package/src/components/App.vue +3 -2
  18. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +153 -0
  19. package/src/components/DocumentAnnotations/AnnotationDetails.vue +21 -4
  20. package/src/components/DocumentAnnotations/AnnotationRow.vue +97 -34
  21. package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +86 -0
  22. package/src/components/DocumentAnnotations/CategorizeModal.vue +24 -2
  23. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +77 -81
  24. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +16 -3
  25. package/src/components/DocumentAnnotations/ExtractingData.vue +3 -3
  26. package/src/components/DocumentAnnotations/index.js +0 -1
  27. package/src/components/DocumentCategory.vue +13 -5
  28. package/src/components/DocumentDashboard.vue +17 -6
  29. package/src/components/DocumentEdit/DocumentEdit.vue +208 -68
  30. package/src/components/DocumentEdit/EditConfirmationModal.vue +54 -0
  31. package/src/components/DocumentEdit/EditPages.vue +29 -18
  32. package/src/components/DocumentEdit/EditSidebar.vue +92 -45
  33. package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
  34. package/src/components/DocumentEdit/SplitInfoBar.vue +19 -0
  35. package/src/components/DocumentEdit/SplitOverview.vue +4 -5
  36. package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +3 -4
  37. package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
  38. package/src/components/DocumentModals/SplittingSuggestionsModal.vue +120 -0
  39. package/src/components/DocumentPage/ActionBar.vue +3 -3
  40. package/src/components/DocumentPage/ScrollingDocument.vue +38 -4
  41. package/src/components/DocumentPage/ScrollingPage.vue +4 -5
  42. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +14 -11
  43. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +35 -30
  44. package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +3 -1
  45. package/src/locales/de.json +19 -6
  46. package/src/locales/en.json +20 -6
  47. package/src/locales/es.json +19 -6
  48. package/src/store/display.js +7 -0
  49. package/src/store/document.js +81 -17
  50. package/src/store/edit.js +67 -48
  51. package/src/store/project.js +14 -14
  52. package/src/components/DocumentAnnotations/ActionButtons.vue +0 -257
  53. package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
@@ -1,75 +1,104 @@
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 SidebarButtons from "./SidebarButtons";
75
+
57
76
  /**
58
77
  * This component renders buttons to rotate single pages or all pages
59
78
  * in edit mode
60
79
  * */
61
-
62
- import { mapState } from "vuex";
63
-
64
80
  export default {
65
81
  name: "EditSidebar",
82
+ components: {
83
+ SidebarButtons,
84
+ },
66
85
  data() {
67
86
  return {
68
87
  buttonDisabled: true,
88
+ tooltipInfo: null,
89
+ newText: this.$t("new"),
90
+ switchStatus: true,
69
91
  };
70
92
  },
93
+ props: {
94
+ splitSuggestionsEnabled: {
95
+ type: Boolean,
96
+ },
97
+ },
71
98
  computed: {
72
99
  ...mapState("edit", ["selectedPages"]),
100
+ ...mapState("document", ["splittingSuggestions", "selectedDocument"]),
101
+ ...mapGetters("document", ["documentHasProposedSplit"]),
73
102
  },
74
103
  watch: {
75
104
  selectedPages(newValue) {
@@ -79,6 +108,24 @@ export default {
79
108
  this.buttonDisabled = true;
80
109
  }
81
110
  },
111
+ switchStatus(newValue) {
112
+ if (this.splittingSuggestions && this.splittingSuggestions.length > 0)
113
+ this.$emit("handle-splitting-suggestions", newValue);
114
+ },
115
+ splitSuggestionsEnabled(newValue) {
116
+ if (!newValue) {
117
+ this.switchStatus = false;
118
+ }
119
+ },
120
+ },
121
+ mounted() {
122
+ this.$nextTick(() => {
123
+ this.switchStatus = this.splitSuggestionsEnabled;
124
+ this.tooltipInfo = this.$t("no_splitting_suggestions");
125
+ if (this.newText) {
126
+ this.newText = this.$t("new").toUpperCase();
127
+ }
128
+ });
82
129
  },
83
130
  methods: {
84
131
  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>
@@ -112,7 +112,7 @@ export default {
112
112
  },
113
113
  computed: {
114
114
  ...mapState("document", ["selectedDocument", "pages"]),
115
- ...mapState("edit", ["updatedDocument", "documentPagesListForEditMode"]),
115
+ ...mapState("edit", ["updatedDocument", "pagesForPostprocess"]),
116
116
  },
117
117
  methods: {
118
118
  handleBackButton() {
@@ -162,11 +162,11 @@ export default {
162
162
  return name.split(".").slice(0, -1).join(".");
163
163
  },
164
164
  getImageUrl(page) {
165
- if (!this.documentPagesListForEditMode || !this.pages || !page) return;
165
+ if (!this.pagesForPostprocess || !this.pages || !page) return;
166
166
 
167
167
  // returns the first thumbnail in the pages array
168
168
  // for each new document
169
- const image = this.documentPagesListForEditMode.find(
169
+ const image = this.pagesForPostprocess.find(
170
170
  (p) => p.number === page.pages[0].number
171
171
  );
172
172
 
@@ -174,8 +174,7 @@ export default {
174
174
  },
175
175
  getRotation(pageId) {
176
176
  // rotate page
177
- return this.documentPagesListForEditMode?.find((p) => p.id === pageId)
178
- ?.angle;
177
+ return this.pagesForPostprocess?.find((p) => p.id === pageId)?.angle;
179
178
  },
180
179
  },
181
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,120 @@
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 { mapGetters, mapState } from "vuex";
37
+ import StarIcon from "../../assets/images/StarIcon";
38
+
39
+ /**
40
+ * This component shows a modal to inform the user about auto-splitting suggestions
41
+ */
42
+ export default {
43
+ name: "SplittingSuggestionsModal",
44
+ components: {
45
+ StarIcon,
46
+ },
47
+ data() {
48
+ return {
49
+ isModalActive: false,
50
+ recommended: this.$t("recommended"),
51
+ };
52
+ },
53
+ computed: {
54
+ ...mapState("document", ["splittingSuggestions", "selectedDocument"]),
55
+ ...mapGetters("document", ["waitingForSplittingConfirmation"]),
56
+ },
57
+ watch: {
58
+ splittingSuggestions(newValue) {
59
+ if (newValue) {
60
+ this.isModalActive = true;
61
+ }
62
+ },
63
+ isModalActive(newValue) {
64
+ if (newValue) {
65
+ this.$nextTick(() => {
66
+ if (
67
+ this.splittingSuggestions &&
68
+ this.splittingSuggestions.length > 0
69
+ ) {
70
+ this.$refs.bodyText.innerHTML = this.$t("split_modal_body", {
71
+ number_of_split_documents: this.splittingSuggestions.length,
72
+ });
73
+ } else {
74
+ this.$refs.bodyText.innerHTML = this.$t(
75
+ "split_modal_no_suggestions"
76
+ );
77
+ }
78
+ });
79
+ }
80
+ },
81
+ },
82
+ mounted() {
83
+ if (this.splittingSuggestions) {
84
+ this.isModalActive = true;
85
+ }
86
+
87
+ this.$nextTick(() => {
88
+ if (this.recommended) {
89
+ this.recommended = this.recommended.toUpperCase();
90
+ }
91
+ });
92
+ },
93
+ methods: {
94
+ closeModal() {
95
+ const updatedDocument = [
96
+ {
97
+ name: this.selectedDocument.data_file_name,
98
+ category: this.selectedDocument.category,
99
+ pages: this.selectedDocument.pages,
100
+ },
101
+ ];
102
+
103
+ this.$store.dispatch("edit/editDocument", updatedDocument);
104
+
105
+ this.$store.dispatch("display/setCategorizeModalIsActive", false);
106
+ this.isModalActive = false;
107
+ },
108
+ handleReviewNow() {
109
+ this.$store.dispatch("edit/enableEditMode");
110
+ this.isModalActive = false;
111
+ },
112
+ },
113
+ };
114
+ </script>
115
+
116
+ <style
117
+ scoped
118
+ lang="scss"
119
+ src="../../assets/scss/splitting_confirmation_modal.scss"
120
+ ></style>
@@ -8,7 +8,7 @@
8
8
  {{ documentActionBar.text }}
9
9
  </div>
10
10
  <div v-if="documentActionBar.action" class="action-button">
11
- <ActionButtons
11
+ <AnnotationActionButtons
12
12
  :save-btn="documentActionBar.action !== null"
13
13
  :is-loading="documentActionBar.loading"
14
14
  :action-bar="true"
@@ -21,14 +21,14 @@
21
21
 
22
22
  <script>
23
23
  import { mapState } from "vuex";
24
- import ActionButtons from "../DocumentAnnotations/ActionButtons";
24
+ import AnnotationActionButtons from "../DocumentAnnotations/AnnotationActionButtons";
25
25
  import ActionIcon from "../../assets/images/ActionIcon";
26
26
 
27
27
  export default {
28
28
  name: "ActionBar",
29
29
  components: {
30
30
  ActionIcon,
31
- ActionButtons,
31
+ AnnotationActionButtons,
32
32
  },
33
33
  computed: {
34
34
  ...mapState("display", ["documentActionBar"]),
@@ -11,11 +11,12 @@
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"
18
18
  :scroll-top="scrollTop"
19
+ ref="scrollingPage"
19
20
  class="scrolling-page"
20
21
  @page-jump="onPageJump"
21
22
  />
@@ -29,7 +30,7 @@
29
30
  </div>
30
31
  </template>
31
32
  <script>
32
- import { mapState } from "vuex";
33
+ import { mapState, mapGetters } from "vuex";
33
34
  import scroll from "../../directives/scroll";
34
35
  import ScrollingPage from "./ScrollingPage";
35
36
  import Toolbar from "./DocumentToolbar";
@@ -49,6 +50,8 @@ export default {
49
50
  return {
50
51
  scrollTop: 0,
51
52
  clientHeight: 0,
53
+ isScolling: false,
54
+ scrollTimeout: null,
52
55
  };
53
56
  },
54
57
 
@@ -58,8 +61,18 @@ export default {
58
61
  "selectedDocument",
59
62
  "loading",
60
63
  ]),
61
- ...mapState("edit", ["editMode", "documentPagesListForEditMode"]),
62
- ...mapState("display", ["scale", "documentActionBar"]),
64
+ ...mapState("edit", [
65
+ "editMode",
66
+ "documentPagesListForEditMode",
67
+ "pagesForPostprocess",
68
+ ]),
69
+ ...mapState("display", [
70
+ "scale",
71
+ "documentActionBar",
72
+ "pageChangedFromThumbnail",
73
+ "currentPage",
74
+ ]),
75
+ ...mapGetters("display", ["visiblePageRange"]),
63
76
 
64
77
  pages() {
65
78
  if (this.selectedDocument) {
@@ -85,6 +98,9 @@ export default {
85
98
  this.scrollTop = 0;
86
99
  },
87
100
  },
101
+ mounted() {
102
+ this.$refs.scrollingDocument.addEventListener("scroll", this.handleScroll);
103
+ },
88
104
 
89
105
  methods: {
90
106
  updateScrollBounds() {
@@ -102,6 +118,24 @@ export default {
102
118
 
103
119
  this.$refs.scrollingDocument.scroll(scrollX, scrollY);
104
120
  },
121
+ handleScroll() {
122
+ if (this.pages.length === 1) return;
123
+
124
+ this.isScrolling = true;
125
+
126
+ clearTimeout(this.scrollTimeout);
127
+
128
+ this.scrollTimeout = setTimeout(() => {
129
+ this.isScrolling = false;
130
+
131
+ if (
132
+ this.pageChangedFromThumbnail &&
133
+ this.visiblePageRange[1] === this.currentPage
134
+ ) {
135
+ this.$store.dispatch("display/setPageChangedFromThumbnail", false);
136
+ }
137
+ }, 300);
138
+ },
105
139
  },
106
140
  };
107
141
  </script>
@@ -44,10 +44,12 @@ export default {
44
44
  previousFocusedAnnotation: null,
45
45
  previousY: null,
46
46
  pageBeingLoaded: false,
47
+ isScrolling: false,
47
48
  };
48
49
  },
49
50
 
50
51
  computed: {
52
+ ...mapState("display", ["pageChangedFromThumbnail"]),
51
53
  ...mapGetters("display", ["visiblePageRange", "bboxToRect"]),
52
54
  ...mapGetters("document", ["scrollDocumentToAnnotation"]),
53
55
 
@@ -117,15 +119,12 @@ export default {
117
119
  }
118
120
  },
119
121
  isElementFocused(focused) {
120
- if (!this.loading && focused) {
122
+ if (!this.loading && focused && !this.pageChangedFromThumbnail) {
121
123
  this.$store.dispatch("display/updateCurrentPage", this.page.number);
122
124
  }
123
125
  },
124
126
  currentPage(number) {
125
- if (
126
- (this.page.number === number || this.page.number === number) &&
127
- !this.isElementFocused
128
- ) {
127
+ if (this.page.number === number && !this.isElementFocused) {
129
128
  this.$emit("page-jump", this.elementTop, 0);
130
129
  }
131
130
  },
@@ -62,7 +62,7 @@ export default {
62
62
  },
63
63
  data() {
64
64
  return {
65
- thumbnailClicked: false,
65
+ thumbnailClicked: null,
66
66
  previousScrollPosition: 0,
67
67
  };
68
68
  },
@@ -76,9 +76,10 @@ export default {
76
76
  },
77
77
  watch: {
78
78
  currentPage(newPage) {
79
- if (newPage && !this.thumbnailClicked) {
80
- this.scrollToThumbnail();
81
- }
79
+ if (!newPage) return;
80
+
81
+ // handle thumbnail selection when scrolling the document
82
+ this.scrollToThumbnail(newPage);
82
83
  },
83
84
  },
84
85
  mounted() {
@@ -94,27 +95,29 @@ export default {
94
95
  methods: {
95
96
  /* Change page if not the currently open and not in modal */
96
97
  changePage(pageNumber) {
97
- this.thumbnailClicked = true;
98
+ this.thumbnailClicked = pageNumber;
98
99
 
99
100
  if (
100
101
  !this.loading &&
101
102
  !this.recalculatingAnnotations &&
102
103
  pageNumber != this.currentPage
103
104
  ) {
104
- this.$store.dispatch(
105
- "display/updateCurrentPage",
106
- parseInt(pageNumber, 10)
107
- );
105
+ this.$store.dispatch("display/setPageChangedFromThumbnail", true);
106
+ this.$store.dispatch("display/updateCurrentPage", pageNumber);
108
107
  }
109
108
  },
110
109
 
111
- scrollToThumbnail() {
110
+ scrollToThumbnail(page) {
112
111
  // select only the active thumbnail
113
112
  const selectedPage = this.$refs.docPage.filter((image) =>
114
113
  image.className.includes("selected")
115
114
  );
116
115
 
117
- if (selectedPage && selectedPage[0]) {
116
+ if (page == this.thumbnailClicked) {
117
+ this.thumbnailClicked = null;
118
+ }
119
+
120
+ if (!this.thumbnailClicked && selectedPage && selectedPage[0]) {
118
121
  selectedPage[0].scrollIntoView();
119
122
  }
120
123
  },