@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.
- package/README.md +12 -0
- package/cypress.config.js +13 -0
- package/dist/css/app.css +1 -1
- package/dist/index.html +1 -1
- package/dist/js/app.js +1 -1
- package/dist/js/app.js.map +1 -1
- package/dist/js/chunk-vendors.js +3 -3
- package/dist/js/chunk-vendors.js.map +1 -1
- package/package.json +5 -1
- package/src/api.js +53 -23
- package/src/assets/images/DraggableIcon.vue +14 -0
- package/src/assets/images/GridIcon.vue +16 -0
- package/src/assets/images/MagicWandIcon.vue +16 -0
- package/src/assets/images/NotFoundIcon.vue +16 -0
- package/src/assets/images/ServerImage.vue +19 -9
- package/src/assets/images/SettingsIcon.vue +14 -0
- package/src/assets/images/SplitZigZag.vue +47 -14
- package/src/assets/images/StarIcon.vue +16 -0
- package/src/assets/scss/ann_set_table_options.scss +26 -0
- package/src/assets/scss/annotation_details.scss +86 -71
- package/src/assets/scss/choose_label_set_modal.scss +1 -1
- package/src/assets/scss/document_annotations.scss +242 -229
- package/src/assets/scss/document_category.scss +12 -7
- package/src/assets/scss/document_dashboard.scss +7 -2
- package/src/assets/scss/document_edit.scss +151 -173
- package/src/assets/scss/document_name.scss +0 -2
- package/src/assets/scss/document_thumbnails.scss +1 -1
- package/src/assets/scss/document_toolbar.scss +23 -1
- package/src/assets/scss/document_top_bar.scss +40 -1
- package/src/assets/scss/edit_page_thumbnail.scss +53 -0
- package/src/assets/scss/multi_ann_table_overlay.scss +38 -0
- package/src/assets/scss/new_annotation.scss +17 -3
- package/src/assets/scss/scrolling_document.scss +1 -1
- package/src/assets/scss/theme.scss +801 -0
- package/src/assets/scss/variables.scss +5 -663
- package/src/components/App.cy.js +7 -0
- package/src/components/App.vue +98 -11
- package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +168 -0
- package/src/components/DocumentAnnotations/AnnotationContent.vue +50 -84
- package/src/components/DocumentAnnotations/AnnotationDetails.vue +37 -12
- package/src/components/DocumentAnnotations/AnnotationRow.vue +244 -199
- package/src/components/DocumentAnnotations/AnnotationSetActionButtons.vue +89 -0
- package/src/components/DocumentAnnotations/ChooseLabelSetModal.vue +4 -2
- package/src/components/DocumentAnnotations/DocumentAnnotations.cy.js +295 -0
- package/src/components/DocumentAnnotations/DocumentAnnotations.vue +195 -146
- package/src/components/DocumentAnnotations/DocumentLabel.vue +46 -9
- package/src/components/DocumentAnnotations/EmptyAnnotation.vue +59 -88
- package/src/components/DocumentAnnotations/ExtractingData.vue +18 -6
- package/src/components/DocumentAnnotations/MultiAnnotationTableOverlay.vue +337 -0
- package/src/components/DocumentAnnotations/index.js +1 -1
- package/src/components/DocumentCategory.vue +89 -65
- package/src/components/DocumentDashboard.vue +59 -48
- package/src/components/DocumentEdit/DocumentEdit.vue +302 -105
- package/src/components/DocumentEdit/EditConfirmationModal.vue +55 -0
- package/src/components/DocumentEdit/EditPageThumbnail.vue +114 -0
- package/src/components/DocumentEdit/EditPages.vue +60 -103
- package/src/components/DocumentEdit/EditSidebar.vue +101 -48
- package/src/components/DocumentEdit/{SplitOverview.vue → RenameAndCategorize.vue} +15 -13
- package/src/components/DocumentEdit/SidebarButtons.vue +53 -0
- package/src/components/DocumentEdit/SplitInfoBar.vue +21 -0
- package/src/components/DocumentEdit/index.js +1 -1
- package/src/components/{DocumentError.vue → DocumentModals/DocumentErrorModal.vue} +9 -8
- package/src/components/{NotOptimizedViewportModal.vue → DocumentModals/NotOptimizedViewportModal.vue} +2 -2
- package/src/components/DocumentPage/ActionBar.vue +3 -3
- package/src/components/DocumentPage/AnnSetTableOptions.vue +110 -0
- package/src/components/DocumentPage/BoxSelection.vue +4 -1
- package/src/components/DocumentPage/DocumentPage.vue +92 -68
- package/src/components/DocumentPage/DocumentToolbar.vue +105 -16
- package/src/components/DocumentPage/DummyPage.vue +9 -7
- package/src/components/DocumentPage/MultiAnnSelection.vue +96 -27
- package/src/components/DocumentPage/NewAnnotation.vue +31 -35
- package/src/components/DocumentPage/ScrollingDocument.vue +46 -5
- package/src/components/DocumentPage/ScrollingPage.vue +5 -6
- package/src/components/DocumentThumbnails/DocumentThumbnails.cy.js +64 -0
- package/src/components/DocumentThumbnails/DocumentThumbnails.vue +53 -13
- package/src/components/DocumentTopBar/DocumentName.vue +16 -4
- package/src/components/DocumentTopBar/DocumentTopBar.vue +86 -15
- package/src/components/DocumentTopBar/DocumentTopBarButtons.vue +99 -72
- package/src/components/DocumentTopBar/KeyboardActionsDescription.vue +6 -3
- package/src/components/DocumentsList/DocumentsList.vue +6 -2
- package/src/components/index.js +1 -0
- package/src/constants.js +2 -1
- package/src/icons.js +45 -0
- package/src/locales/de.json +48 -21
- package/src/locales/en.json +37 -11
- package/src/locales/es.json +41 -13
- package/src/main.js +5 -66
- package/src/store/category.js +20 -36
- package/src/store/display.js +74 -1
- package/src/store/document.js +305 -109
- package/src/store/edit.js +160 -61
- package/src/store/project.js +46 -16
- package/src/store/selection.js +42 -10
- package/src/utils/utils.js +36 -0
- package/dist/css/chunk-vendors.css +0 -5
- package/src/assets/scss/categorize_modal.scss +0 -45
- package/src/assets/scss/main.scss +0 -24
- package/src/components/DocumentAnnotations/ActionButtons.vue +0 -250
- package/src/components/DocumentAnnotations/CategorizeModal.vue +0 -219
- package/src/components/DocumentAnnotations/RejectedLabels.vue +0 -96
- 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
|
|
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
|
|
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
|
|
60
|
+
<div
|
|
61
|
+
:class="['zoom-in', 'icon', isZoomInExceeding && 'zoom-disabled']"
|
|
62
|
+
@click.prevent.stop="zoomIn"
|
|
63
|
+
>
|
|
31
64
|
<PlusIcon />
|
|
32
65
|
</div>
|
|
33
|
-
<div
|
|
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(
|
|
156
|
+
this.updateScale(this.scale + this.defaultPercentage);
|
|
111
157
|
},
|
|
112
158
|
zoomOut() {
|
|
113
|
-
if (this.currentPercentage ===
|
|
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(
|
|
167
|
+
this.updateScale(this.scale - this.defaultPercentage);
|
|
119
168
|
},
|
|
120
169
|
fitAuto() {
|
|
121
|
-
|
|
170
|
+
// exit edit mode of Annotation if changing zoom during editing
|
|
171
|
+
this.cancelAnnotationEditMode();
|
|
122
172
|
|
|
123
173
|
// Always set to 50%
|
|
124
|
-
this.
|
|
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 {
|
|
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
|
|
111
|
-
y: y
|
|
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.$
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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 || !
|
|
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 {
|
|
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].
|
|
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].
|
|
170
|
+
return this.newAnnotation[0].scaled.y > heightOfPopup
|
|
168
171
|
? top
|
|
169
|
-
: this.newAnnotation[0].
|
|
170
|
-
this.newAnnotation[0].
|
|
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].
|
|
176
|
-
this.newAnnotation[0].
|
|
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
|
-
|
|
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("
|
|
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 {
|
|
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.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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 ?
|
|
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
|
-
...
|
|
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
|
|
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", ["
|
|
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
|
},
|