@konfuzio/document-validation-ui 0.1.14 → 0.1.15

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 (101) hide show
  1. package/README.md +12 -0
  2. package/cypress.config.js +13 -0
  3. package/dist/css/app.css +1 -1
  4. package/dist/index.html +1 -1
  5. package/dist/js/app.js +1 -1
  6. package/dist/js/app.js.map +1 -1
  7. package/dist/js/chunk-vendors.js +3 -3
  8. package/dist/js/chunk-vendors.js.map +1 -1
  9. package/package.json +5 -1
  10. package/src/api.js +53 -23
  11. package/src/assets/images/DraggableIcon.vue +14 -0
  12. package/src/assets/images/GridIcon.vue +16 -0
  13. package/src/assets/images/MagicWandIcon.vue +16 -0
  14. package/src/assets/images/NotFoundIcon.vue +16 -0
  15. package/src/assets/images/ServerImage.vue +19 -9
  16. package/src/assets/images/SettingsIcon.vue +14 -0
  17. package/src/assets/images/SplitZigZag.vue +47 -14
  18. package/src/assets/images/StarIcon.vue +16 -0
  19. package/src/assets/scss/ann_set_table_options.scss +26 -0
  20. package/src/assets/scss/annotation_details.scss +86 -71
  21. package/src/assets/scss/choose_label_set_modal.scss +1 -1
  22. package/src/assets/scss/document_annotations.scss +242 -229
  23. package/src/assets/scss/document_category.scss +12 -7
  24. package/src/assets/scss/document_dashboard.scss +7 -2
  25. package/src/assets/scss/document_edit.scss +151 -173
  26. package/src/assets/scss/document_name.scss +0 -2
  27. package/src/assets/scss/document_thumbnails.scss +1 -1
  28. package/src/assets/scss/document_toolbar.scss +23 -1
  29. package/src/assets/scss/document_top_bar.scss +40 -1
  30. package/src/assets/scss/edit_page_thumbnail.scss +53 -0
  31. package/src/assets/scss/multi_ann_table_overlay.scss +38 -0
  32. package/src/assets/scss/new_annotation.scss +17 -3
  33. package/src/assets/scss/scrolling_document.scss +1 -1
  34. package/src/assets/scss/theme.scss +801 -0
  35. package/src/assets/scss/variables.scss +5 -663
  36. package/src/components/App.cy.js +7 -0
  37. package/src/components/App.vue +98 -11
  38. package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +168 -0
  39. package/src/components/DocumentAnnotations/AnnotationContent.vue +50 -84
  40. package/src/components/DocumentAnnotations/AnnotationDetails.vue +37 -12
  41. package/src/components/DocumentAnnotations/AnnotationRow.vue +244 -199
  42. package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +89 -0
  43. package/src/components/DocumentAnnotations/ChooseLabelSetModal.vue +4 -2
  44. package/src/components/DocumentAnnotations/DocumentAnnotations.cy.js +295 -0
  45. package/src/components/DocumentAnnotations/DocumentAnnotations.vue +195 -146
  46. package/src/components/DocumentAnnotations/DocumentLabel.vue +46 -9
  47. package/src/components/DocumentAnnotations/EmptyAnnotation.vue +59 -88
  48. package/src/components/DocumentAnnotations/ExtractingData.vue +18 -6
  49. package/src/components/DocumentAnnotations/MultiAnnotationTableOverlay.vue +337 -0
  50. package/src/components/DocumentAnnotations/index.js +1 -1
  51. package/src/components/DocumentCategory.vue +89 -65
  52. package/src/components/DocumentDashboard.vue +59 -48
  53. package/src/components/DocumentEdit/DocumentEdit.vue +302 -105
  54. package/src/components/DocumentEdit/EditConfirmationModal.vue +55 -0
  55. package/src/components/DocumentEdit/EditPageThumbnail.vue +114 -0
  56. package/src/components/DocumentEdit/EditPages.vue +60 -103
  57. package/src/components/DocumentEdit/EditSidebar.vue +101 -48
  58. package/src/components/DocumentEdit/{SplitOverview.vue → RenameAndCategorize.vue} +15 -13
  59. package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
  60. package/src/components/DocumentEdit/SplitInfoBar.vue +21 -0
  61. package/src/components/DocumentEdit/index.js +1 -1
  62. package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +9 -8
  63. package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
  64. package/src/components/DocumentPage/ActionBar.vue +3 -3
  65. package/src/components/DocumentPage/AnnSetTableOptions.vue +110 -0
  66. package/src/components/DocumentPage/BoxSelection.vue +4 -1
  67. package/src/components/DocumentPage/DocumentPage.vue +92 -68
  68. package/src/components/DocumentPage/DocumentToolbar.vue +105 -16
  69. package/src/components/DocumentPage/DummyPage.vue +9 -7
  70. package/src/components/DocumentPage/MultiAnnSelection.vue +96 -27
  71. package/src/components/DocumentPage/NewAnnotation.vue +31 -35
  72. package/src/components/DocumentPage/ScrollingDocument.vue +46 -5
  73. package/src/components/DocumentPage/ScrollingPage.vue +5 -6
  74. package/src/components/DocumentThumbnails/DocumentThumbnails.cy.js +64 -0
  75. package/src/components/DocumentThumbnails/DocumentThumbnails.vue +53 -13
  76. package/src/components/DocumentTopBar/DocumentName.vue +16 -4
  77. package/src/components/DocumentTopBar/DocumentTopBar.vue +86 -15
  78. package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +99 -72
  79. package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +6 -3
  80. package/src/components/DocumentsList/DocumentsList.vue +6 -2
  81. package/src/components/index.js +1 -0
  82. package/src/constants.js +2 -1
  83. package/src/icons.js +45 -0
  84. package/src/locales/de.json +48 -21
  85. package/src/locales/en.json +37 -11
  86. package/src/locales/es.json +41 -13
  87. package/src/main.js +5 -66
  88. package/src/store/category.js +20 -36
  89. package/src/store/display.js +74 -1
  90. package/src/store/document.js +305 -109
  91. package/src/store/edit.js +160 -61
  92. package/src/store/project.js +46 -16
  93. package/src/store/selection.js +42 -10
  94. package/src/utils/utils.js +36 -0
  95. package/dist/css/chunk-vendors.css +0 -5
  96. package/src/assets/scss/categorize_modal.scss +0 -45
  97. package/src/assets/scss/main.scss +0 -24
  98. package/src/components/DocumentAnnotations/ActionButtons.vue +0 -250
  99. package/src/components/DocumentAnnotations/CategorizeModal.vue +0 -219
  100. package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
  101. package/src/components/DocumentPage/MultiAnnotationTablePopup.vue +0 -253
@@ -9,7 +9,7 @@
9
9
  class="top-aligned"
10
10
  >
11
11
  <div
12
- v-if="!editMode && !publicView"
12
+ v-if="!editMode && !publicView && !isDocumentReviewed"
13
13
  :class="[
14
14
  'icons icons-left',
15
15
  editModeDisabled && 'edit-mode-disabled',
@@ -22,15 +22,51 @@
22
22
  <span class="edit-text">{{ $t("edit") }}</span>
23
23
  </div>
24
24
  </b-tooltip>
25
- <div v-if="!editMode && !publicView" class="toolbar-divider" />
25
+ <div
26
+ v-if="!editMode && !publicView && !isDocumentReviewed"
27
+ class="toolbar-divider"
28
+ />
29
+
30
+ <div v-if="!publicView" class="download-file icons">
31
+ <b-dropdown aria-role="list" position="is-top-right" scrollable>
32
+ <template #trigger>
33
+ <b-icon icon="download" size="small" class="download-file" />
34
+ </template>
35
+
36
+ <b-dropdown-item aria-role="listitem" @click="handleDownloadFile()">{{
37
+ $t("original_file")
38
+ }}</b-dropdown-item>
39
+ <b-dropdown-item
40
+ aria-role="listitem"
41
+ @click="handleDownloadFile('ocr')"
42
+ >{{ $t("pdf_file") }}</b-dropdown-item
43
+ >
44
+ </b-dropdown>
45
+ </div>
46
+
47
+ <div v-if="!publicView" class="toolbar-divider" />
48
+
26
49
  <div class="icons icons-right">
27
- <div class="fit-zoom icon" @click.prevent.stop="fitAuto">
50
+ <div
51
+ :class="[
52
+ 'fit-zoom',
53
+ 'icon',
54
+ currentPercentage === 50 && 'zoom-disabled',
55
+ ]"
56
+ @click.prevent.stop="fitAuto"
57
+ >
28
58
  <FitZoomIcon />
29
59
  </div>
30
- <div class="zoom-in icon" @click.prevent.stop="zoomIn">
60
+ <div
61
+ :class="['zoom-in', 'icon', isZoomInExceeding && 'zoom-disabled']"
62
+ @click.prevent.stop="zoomIn"
63
+ >
31
64
  <PlusIcon />
32
65
  </div>
33
- <div class="zoom-out icon" @click.prevent.stop="zoomOut">
66
+ <div
67
+ :class="['zoom-out icon', isZoomOutExceeding && 'zoom-disabled']"
68
+ @click.prevent.stop="zoomOut"
69
+ >
34
70
  <MinusIcon />
35
71
  </div>
36
72
  <div class="percentage">
@@ -47,6 +83,7 @@ import FitZoomIcon from "../../assets/images/FitZoomIcon";
47
83
  import PlusIcon from "../../assets/images/PlusIcon";
48
84
  import MinusIcon from "../../assets/images/MinusIcon";
49
85
  import EditDocIcon from "../../assets/images/EditDocIcon";
86
+ import api from "../../api";
50
87
 
51
88
  export default {
52
89
  name: "DocumentToolbar",
@@ -58,8 +95,8 @@ export default {
58
95
  },
59
96
  data() {
60
97
  return {
61
- defaultScale: null,
62
98
  currentPercentage: 100,
99
+ maxPercentage: 500,
63
100
  defaultPercentage: 0.25,
64
101
  fitPercentage: 0.5,
65
102
  toolbarModalOpen: true,
@@ -75,7 +112,13 @@ export default {
75
112
  "recalculatingAnnotations",
76
113
  "publicView",
77
114
  ]),
78
- ...mapGetters("document", ["documentCannotBeEdited"]),
115
+ ...mapGetters("document", ["documentCannotBeEdited", "isDocumentReviewed"]),
116
+ isZoomInExceeding() {
117
+ return this.currentPercentage === this.maxPercentage;
118
+ },
119
+ isZoomOutExceeding() {
120
+ return this.currentPercentage === this.defaultPercentage * 100;
121
+ },
79
122
  },
80
123
  watch: {
81
124
  selectedDocument(newValue) {
@@ -85,8 +128,6 @@ export default {
85
128
  },
86
129
  },
87
130
  mounted() {
88
- this.defaultScale = this.scale;
89
-
90
131
  if (this.selectedDocument) {
91
132
  if (this.documentCannotBeEdited(this.selectedDocument)) {
92
133
  this.editModeDisabled = true;
@@ -103,33 +144,81 @@ export default {
103
144
  methods: {
104
145
  handleEdit() {
105
146
  if (this.editModeDisabled) return;
147
+ this.$store.dispatch("selection/disableSelection");
106
148
  this.$store.dispatch("edit/enableEditMode");
107
149
  },
108
150
  zoomIn() {
151
+ if (this.currentPercentage === this.maxPercentage) return;
152
+
153
+ // exit edit mode of Annotation if changing zoom during editing
154
+ this.cancelAnnotationEditMode();
109
155
  this.currentPercentage += this.defaultPercentage * 100;
110
- this.updateScale((this.defaultScale * this.currentPercentage) / 100);
156
+ this.updateScale(this.scale + this.defaultPercentage);
111
157
  },
112
158
  zoomOut() {
113
- if (this.currentPercentage === 25) {
159
+ if (this.currentPercentage === this.defaultPercentage * 100) {
114
160
  return;
115
161
  }
116
162
 
163
+ // exit edit mode of Annotation if changing zoom during editing
164
+ this.cancelAnnotationEditMode();
165
+
117
166
  this.currentPercentage -= this.defaultPercentage * 100;
118
- this.updateScale((this.defaultScale * this.currentPercentage) / 100);
167
+ this.updateScale(this.scale - this.defaultPercentage);
119
168
  },
120
169
  fitAuto() {
121
- if (this.currentPercentage === 50 || !this.defaultScale) return;
170
+ // exit edit mode of Annotation if changing zoom during editing
171
+ this.cancelAnnotationEditMode();
122
172
 
123
173
  // Always set to 50%
124
- this.updateScale(this.defaultScale * this.fitPercentage);
125
-
126
- this.currentPercentage = this.fitPercentage * 100;
174
+ this.currentPercentage = 50;
175
+ this.$store.dispatch("display/updateFit", "all");
127
176
  },
128
177
  updateScale(scale) {
129
178
  this.$store.dispatch("display/updateFit", "custom").then(() => {
130
179
  this.$store.dispatch("display/updateScale", { scale });
131
180
  });
132
181
  },
182
+ handleDownloadFile(fileType) {
183
+ let fileUrl;
184
+ // get the file name without the extension
185
+ let fileName = this.getFileName(this.selectedDocument.data_file_name);
186
+
187
+ if (fileType === "ocr") {
188
+ fileUrl = this.selectedDocument.file_url;
189
+ fileName = `${fileName}_${fileType}`;
190
+ } else {
191
+ fileUrl = `/doc/show-original/${this.selectedDocument.id}/`;
192
+ }
193
+
194
+ // Automatically download original or ocr files
195
+ return api
196
+ .makeFileRequest(fileUrl)
197
+ .then((myBlob) => {
198
+ const url = URL.createObjectURL(myBlob);
199
+ const link = document.createElement("a");
200
+ link.href = url;
201
+ link.setAttribute("download", fileName);
202
+ link.click();
203
+ URL.revokeObjectURL(link.href);
204
+ })
205
+ .catch((error) => {
206
+ this.$store.dispatch("document/createErrorMessage", {
207
+ error,
208
+ serverErrorMessage: this.$t("server_error"),
209
+ defaultErrorMessage: this.$t("error_downloading_file"),
210
+ });
211
+ console.log(error);
212
+ });
213
+ },
214
+ getFileName(fileName) {
215
+ return fileName.split(".").slice(0, -1).join(".");
216
+ },
217
+ cancelAnnotationEditMode() {
218
+ this.$store.dispatch("document/resetEditAnnotation");
219
+ this.$store.dispatch("selection/disableSelection");
220
+ this.$store.dispatch("selection/setSelectedEntities", null);
221
+ },
133
222
  },
134
223
  };
135
224
  </script>
@@ -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>
@@ -44,7 +44,7 @@
44
44
 
45
45
  <script>
46
46
  import { mapGetters, mapState, mapActions } from "vuex";
47
- import { ChooseLabelSetModal } from "../DocumentAnnotations";
47
+ import { table_reference_api } from "../../store/document";
48
48
 
49
49
  export default {
50
50
  props: {
@@ -105,15 +105,18 @@ export default {
105
105
  if (y < this.selection.start.y) {
106
106
  y = this.selection.start.y;
107
107
  }
108
+ x = x - this.buttonWidth;
109
+ y = y + marginTop;
108
110
 
109
111
  return {
110
- x: x - this.buttonWidth,
111
- y: y + marginTop,
112
+ x: x > 0 ? x : 0,
113
+ y: y > 0 ? y : 0,
112
114
  height: this.buttonHeight,
113
115
  width: this.buttonWidth,
114
116
  };
115
117
  },
116
118
  ...mapState("selection", ["selection", "isSelecting"]),
119
+ ...mapState("document", ["documentId"]),
117
120
  ...mapGetters("display", ["clientToBbox"]),
118
121
  ...mapGetters("document", ["entitiesOnSelection"]),
119
122
  },
@@ -128,32 +131,54 @@ export default {
128
131
  },
129
132
  methods: {
130
133
  openMultiAnnotationModal() {
131
- this.$buefy.modal.open({
132
- parent: this.$parent,
133
- component: ChooseLabelSetModal,
134
- hasModalCard: true,
135
- trapFocus: true,
136
- canCancel: false,
137
- customClass: "invisible-parent-modal",
138
- props: { isMultipleAnnotations: true },
139
- events: {
140
- labelSet: this.chooseLabelSet,
141
- },
134
+ this.$store.dispatch("display/showChooseLabelSetModal", {
135
+ show: true,
136
+ isMultipleAnnotations: true,
137
+ finish: this.submitAnnotations,
142
138
  });
143
139
  },
144
- chooseLabelSet(labelSet) {
145
- const tableSelection = {
146
- labelSet,
147
- position: {
148
- x: this.selection.start.x,
149
- y: this.selection.start.y,
150
- width: this.selection.end.x - this.selection.start.x,
151
- height: this.selection.end.y - this.selection.start.y,
152
- },
153
- entities: this.entities,
154
- };
155
- this.$store.dispatch("selection/disableSelection");
156
- this.$emit("finished", tableSelection);
140
+
141
+ async submitAnnotations(labelSet) {
142
+ const columns = labelSet.labels.map((label) => {
143
+ return {
144
+ field: `${label.id}`,
145
+ label: label.name,
146
+ centered: true,
147
+ };
148
+ });
149
+
150
+ const orderedEntities = this.processRows(columns);
151
+
152
+ const annotations = [];
153
+
154
+ orderedEntities.forEach((orderedEntity) => {
155
+ annotations.push({
156
+ document: this.documentId,
157
+ span: orderedEntity.spans,
158
+ label: orderedEntity.label_id,
159
+ is_correct: true,
160
+ revised: false,
161
+ label_set: labelSet.id,
162
+ set_reference: orderedEntity.row_index,
163
+ origin: table_reference_api,
164
+ });
165
+ });
166
+
167
+ this.$store
168
+ .dispatch("document/createAnnotation", annotations)
169
+ .then(() => {
170
+ this.$store.dispatch("selection/disableSelection");
171
+ this.$emit("finished");
172
+ })
173
+ .catch((error) => {
174
+ this.$store.dispatch("document/createErrorMessage", {
175
+ error,
176
+ serverErrorMessage: this.$t("server_error"),
177
+ defaultErrorMessage: this.$t("error_creating_multi_ann"),
178
+ });
179
+ this.$store.dispatch("selection/disableSelection");
180
+ this.$emit("finished");
181
+ });
157
182
  },
158
183
 
159
184
  onButtonEnter() {
@@ -296,6 +321,50 @@ export default {
296
321
 
297
322
  this.entities = cols;
298
323
  },
324
+
325
+ processRows(columns) {
326
+ const orderedEntities = []; // this will match the order of entities in the table so we have a way of tracking them once we submit
327
+ let rowIndex = 0;
328
+
329
+ Object.entries(this.entities).forEach(([key, groupedEntity]) => {
330
+ let row = null;
331
+ columns.forEach((column, index) => {
332
+ let spans = [];
333
+ if (
334
+ Object.entries(groupedEntity)[index] &&
335
+ Object.entries(groupedEntity)[index].length > 0
336
+ ) {
337
+ spans = Object.entries(groupedEntity)[index][1];
338
+ }
339
+ const entityExists = spans.length > 0;
340
+
341
+ let textContent = "";
342
+
343
+ spans.forEach((entity) => {
344
+ textContent = `${textContent} ${entity.offset_string}`;
345
+ });
346
+
347
+ row = {
348
+ ...row,
349
+ [column.field]: textContent,
350
+ };
351
+ if (entityExists) {
352
+ const customEntity = {
353
+ spans: [...spans],
354
+ label_id: column.field,
355
+ row_index: rowIndex,
356
+ };
357
+
358
+ orderedEntities.push(customEntity);
359
+ }
360
+ });
361
+ if (row !== null) {
362
+ rowIndex++;
363
+ }
364
+ });
365
+ return orderedEntities;
366
+ },
367
+
299
368
  ...mapActions("selection", ["moveSelection"]),
300
369
  },
301
370
  };
@@ -5,9 +5,11 @@
5
5
  v-model="selectedSet"
6
6
  aria-role="list"
7
7
  :class="[
8
+ 'annotation-dropdown',
8
9
  'no-padding-bottom',
9
10
  setsList.length === 0 ? 'no-padding-top' : '',
10
11
  ]"
12
+ scrollable
11
13
  >
12
14
  <template #trigger>
13
15
  <b-button
@@ -69,7 +71,8 @@
69
71
  v-model="selectedLabel"
70
72
  aria-role="list"
71
73
  :disabled="!labels || labels.length === 0"
72
- class="label-dropdown"
74
+ scrollable
75
+ class="label-dropdown annotation-dropdown"
73
76
  >
74
77
  <template #trigger>
75
78
  <b-button
@@ -110,7 +113,7 @@
110
113
  type="is-primary"
111
114
  class="popup-button primary-button"
112
115
  :label="$t('save')"
113
- :disabled="loading || !getTextFromEntities || !selectedLabel"
116
+ :disabled="loading || !spanSelection || !selectedLabel"
114
117
  @click.prevent="save"
115
118
  />
116
119
  </div>
@@ -126,7 +129,7 @@ const margin = 12;
126
129
  const widthOfPopup = 205;
127
130
 
128
131
  import { mapGetters, mapState } from "vuex";
129
- import { ChooseLabelSetModal } from "../DocumentAnnotations";
132
+ import { MULTI_ANN_TABLE_FEATURE } from "../../constants";
130
133
 
131
134
  export default {
132
135
  props: {
@@ -158,22 +161,22 @@ export default {
158
161
  ...mapGetters("document", [
159
162
  "numberOfAnnotationSetGroup",
160
163
  "labelsFilteredForAnnotationCreation",
161
- "getTextFromEntities",
162
164
  ]),
165
+ ...mapState("selection", ["spanSelection"]),
163
166
  top() {
164
- const top = this.newAnnotation[0].entity.scaled.y - heightOfPopup; // subtract the height of the popup plus some margin
167
+ const top = this.newAnnotation[0].scaled.y - heightOfPopup; // subtract the height of the popup plus some margin
165
168
 
166
169
  //check if the popup will not go off the container on the top
167
- return this.newAnnotation[0].entity.scaled.y > heightOfPopup
170
+ return this.newAnnotation[0].scaled.y > heightOfPopup
168
171
  ? top
169
- : this.newAnnotation[0].entity.scaled.y +
170
- this.newAnnotation[0].entity.scaled.height +
172
+ : this.newAnnotation[0].scaled.y +
173
+ this.newAnnotation[0].scaled.height +
171
174
  margin;
172
175
  },
173
176
  left() {
174
177
  const left =
175
- this.newAnnotation[0].entity.scaled.x +
176
- this.newAnnotation[0].entity.scaled.width / 2 -
178
+ this.newAnnotation[0].scaled.x +
179
+ this.newAnnotation[0].scaled.width / 2 -
177
180
  widthOfPopup / 2; // add the entity half width to be centered and then subtract half the width of the popup
178
181
 
179
182
  //check if the popup will not go off the container
@@ -186,7 +189,15 @@ export default {
186
189
  }
187
190
  },
188
191
  textFromEntities() {
189
- return this.getTextFromEntities();
192
+ if (!this.spanSelection) return;
193
+
194
+ // get array of all offset strings
195
+ let text = this.spanSelection.map((span) => {
196
+ return span.offset_string;
197
+ });
198
+
199
+ // join all the strings to become a single string of text
200
+ return text.join().split(",").join(" ");
190
201
  },
191
202
  },
192
203
  watch: {
@@ -210,13 +221,16 @@ export default {
210
221
  },
211
222
  methods: {
212
223
  close() {
213
- this.$store.dispatch("document/setSelectedEntities", null);
224
+ this.$store.dispatch("selection/setSelectedEntities", null);
214
225
  this.$emit("close");
215
226
  },
216
227
  save() {
217
228
  this.loading = true;
218
229
  const span = this.newAnnotation.flatMap((ann) => {
219
- return { ...ann.entity.original, offset_string: ann.content };
230
+ return {
231
+ ...ann.original,
232
+ offset_string: ann.original.offset_string,
233
+ };
220
234
  });
221
235
 
222
236
  const annotationToCreate = {
@@ -247,15 +261,7 @@ export default {
247
261
  this.loading = false;
248
262
  });
249
263
  },
250
- disableLabelSetModalShowing() {
251
- // timeout to stop propagation of click event
252
- setTimeout(() => {
253
- this.isAnnSetModalShowing = false;
254
- }, 500);
255
- },
256
264
  chooseLabelSet(labelSet) {
257
- this.disableLabelSetModalShowing();
258
-
259
265
  const newSet = {
260
266
  label_set: labelSet,
261
267
  labels: labelSet.labels,
@@ -265,20 +271,10 @@ export default {
265
271
  this.selectedSet = newSet;
266
272
  },
267
273
  openAnnotationSetCreation() {
268
- this.isAnnSetModalShowing = true;
269
-
270
- this.$buefy.modal.open({
271
- parent: this.$parent,
272
- component: ChooseLabelSetModal,
273
- hasModalCard: true,
274
- trapFocus: true,
275
- canCancel: false,
276
- onCancel: this.disableLabelSetModalShowing,
277
- customClass: "invisible-parent-modal",
278
- events: {
279
- labelSet: this.chooseLabelSet,
280
- close: this.disableLabelSetModalShowing,
281
- },
274
+ this.$store.dispatch("display/showChooseLabelSetModal", {
275
+ show: true,
276
+ isMultipleAnnotations: MULTI_ANN_TABLE_FEATURE,
277
+ finish: this.chooseLabelSet,
282
278
  });
283
279
  },
284
280
  setTooltipText() {
@@ -11,8 +11,9 @@
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
+ ref="scrollingPage"
16
17
  :page="page"
17
18
  :client-height="clientHeight"
18
19
  :scroll-top="scrollTop"
@@ -20,6 +21,7 @@
20
21
  @page-jump="onPageJump"
21
22
  />
22
23
  </div>
24
+
23
25
  <div v-else class="loading-page">
24
26
  <b-skeleton width="100%" height="1000px" />
25
27
  </div>
@@ -29,7 +31,7 @@
29
31
  </div>
30
32
  </template>
31
33
  <script>
32
- import { mapState } from "vuex";
34
+ import { mapState, mapGetters } from "vuex";
33
35
  import scroll from "../../directives/scroll";
34
36
  import ScrollingPage from "./ScrollingPage";
35
37
  import Toolbar from "./DocumentToolbar";
@@ -49,6 +51,8 @@ export default {
49
51
  return {
50
52
  scrollTop: 0,
51
53
  clientHeight: 0,
54
+ isScolling: false,
55
+ scrollTimeout: null,
52
56
  };
53
57
  },
54
58
 
@@ -57,9 +61,20 @@ export default {
57
61
  "recalculatingAnnotations",
58
62
  "selectedDocument",
59
63
  "loading",
64
+ "annotationSets",
65
+ ]),
66
+ ...mapState("edit", [
67
+ "editMode",
68
+ "documentPagesListForEditMode",
69
+ "pagesForPostprocess",
70
+ ]),
71
+ ...mapState("display", [
72
+ "scale",
73
+ "documentActionBar",
74
+ "pageChangedFromThumbnail",
75
+ "currentPage",
60
76
  ]),
61
- ...mapState("edit", ["editMode", "documentPagesListForEditMode"]),
62
- ...mapState("display", ["scale", "documentActionBar"]),
77
+ ...mapGetters("display", ["visiblePageRange"]),
63
78
 
64
79
  pages() {
65
80
  if (this.selectedDocument) {
@@ -69,7 +84,12 @@ export default {
69
84
  }
70
85
  },
71
86
  showToolbar() {
72
- return this.pages.length > 0 && this.scale && !this.documentActionBar;
87
+ return (
88
+ !this.loading &&
89
+ this.pages.length > 0 &&
90
+ this.scale &&
91
+ !this.documentActionBar
92
+ );
73
93
  },
74
94
  showActionBar() {
75
95
  return this.documentActionBar !== null;
@@ -80,6 +100,9 @@ export default {
80
100
  this.scrollTop = 0;
81
101
  },
82
102
  },
103
+ mounted() {
104
+ this.$refs.scrollingDocument.addEventListener("scroll", this.handleScroll);
105
+ },
83
106
 
84
107
  methods: {
85
108
  updateScrollBounds() {
@@ -97,6 +120,24 @@ export default {
97
120
 
98
121
  this.$refs.scrollingDocument.scroll(scrollX, scrollY);
99
122
  },
123
+ handleScroll() {
124
+ if (this.pages.length === 1) return;
125
+
126
+ this.isScrolling = true;
127
+
128
+ clearTimeout(this.scrollTimeout);
129
+
130
+ this.scrollTimeout = setTimeout(() => {
131
+ this.isScrolling = false;
132
+
133
+ if (
134
+ this.pageChangedFromThumbnail &&
135
+ this.visiblePageRange[1] === this.currentPage
136
+ ) {
137
+ this.$store.dispatch("display/setPageChangedFromThumbnail", false);
138
+ }
139
+ }, 300);
140
+ },
100
141
  },
101
142
  };
102
143
  </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
 
@@ -88,7 +90,7 @@ export default {
88
90
  return this.scrollTop + this.clientHeight;
89
91
  },
90
92
 
91
- ...mapState("display", ["scale", "currentPage"]),
93
+ ...mapState("display", ["currentPage"]),
92
94
  ...mapState("document", ["pages", "documentAnnotationSelected", "loading"]),
93
95
  ...mapState("edit", ["editMode"]),
94
96
  },
@@ -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
  },