@konfuzio/document-validation-ui 0.1.24-dev.0 → 0.1.24-dev.2
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/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 +1 -1
- package/dist/js/chunk-vendors.js.map +1 -1
- package/package.json +1 -1
- package/src/assets/scss/document_annotations.scss +5 -1
- package/src/assets/scss/document_search_bar.scss +71 -0
- package/src/assets/scss/document_toolbar.scss +2 -1
- package/src/assets/scss/theme.scss +2 -1
- package/src/assets/scss/variables.scss +1 -0
- package/src/components/App.vue +16 -0
- package/src/components/DocumentAnnotations/AnnotationActionButtons.vue +10 -0
- package/src/components/DocumentAnnotations/AnnotationRow.vue +11 -6
- package/src/components/DocumentAnnotations/DocumentAnnotations.vue +4 -5
- package/src/components/DocumentPage/DocumentPage.cy.js +82 -1
- package/src/components/DocumentPage/DocumentPage.vue +41 -1
- package/src/components/DocumentPage/DocumentToolbar.cy.js +12 -0
- package/src/components/DocumentPage/DocumentToolbar.vue +9 -1
- package/src/components/DocumentPage/NewAnnotation.vue +6 -2
- package/src/components/DocumentPage/ScrollingDocument.vue +6 -0
- package/src/components/DocumentPage/ScrollingPage.vue +26 -4
- package/src/components/DocumentPage/SearchBar.vue +130 -0
- package/src/components/DocumentTopBar/DocumentName.vue +10 -2
- package/src/icons.js +3 -1
- package/src/locales/de.json +7 -1
- package/src/locales/en.json +8 -1
- package/src/locales/es.json +7 -1
- package/src/store/display.js +114 -0
- package/src/store/document.js +1 -2
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div id="document-search">
|
|
3
|
+
<div class="search-container">
|
|
4
|
+
<input
|
|
5
|
+
ref="searchInput"
|
|
6
|
+
v-model="search"
|
|
7
|
+
:placeholder="$t('search')"
|
|
8
|
+
class="search-input"
|
|
9
|
+
@keyup.13="focusSearchResult(1)"
|
|
10
|
+
/>
|
|
11
|
+
<div v-if="searchLoading" class="search-loading">
|
|
12
|
+
<b-icon icon="spinner" class="fa-spin loading-icon-size spinner" />
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div
|
|
16
|
+
v-else-if="
|
|
17
|
+
searchResults.length === 0 && search.length >= minSearchLength
|
|
18
|
+
"
|
|
19
|
+
class="search-no-results"
|
|
20
|
+
>
|
|
21
|
+
{{ $t("no_results") }}
|
|
22
|
+
</div>
|
|
23
|
+
<div v-else class="search-navigation">
|
|
24
|
+
<span v-if="searchBelowMinimum" class="search-counters">
|
|
25
|
+
{{ $t("search_below_minimum") }}
|
|
26
|
+
</span>
|
|
27
|
+
<span v-else class="search-counters"
|
|
28
|
+
>{{ currentCounter }}/{{ searchResults.length }}</span
|
|
29
|
+
>
|
|
30
|
+
<b-button
|
|
31
|
+
v-if="!searchBelowMinimum"
|
|
32
|
+
class="is-ghost is-small next-search"
|
|
33
|
+
:disabled="!searchResults.length || searchResults.length <= 1"
|
|
34
|
+
@click="focusSearchResult(1)"
|
|
35
|
+
><b-icon icon="angle-down" class="is-small"
|
|
36
|
+
/></b-button>
|
|
37
|
+
|
|
38
|
+
<b-button
|
|
39
|
+
v-if="!searchBelowMinimum"
|
|
40
|
+
class="is-ghost is-small previous-search"
|
|
41
|
+
:disabled="!searchResults.length || searchResults.length <= 1"
|
|
42
|
+
@click="focusSearchResult(-1)"
|
|
43
|
+
><b-icon icon="angle-up" class="is-small"
|
|
44
|
+
/></b-button>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="search-close">
|
|
47
|
+
<b-button class="is-ghost is-small" @click="closeSearch">
|
|
48
|
+
<b-icon icon="xmark" class="is-small" />
|
|
49
|
+
</b-button>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
|
|
55
|
+
<script>
|
|
56
|
+
import { mapState } from "vuex";
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
name: "SearchBar",
|
|
60
|
+
data() {
|
|
61
|
+
return {
|
|
62
|
+
search: "",
|
|
63
|
+
minSearchLength: 3,
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
computed: {
|
|
67
|
+
...mapState("display", [
|
|
68
|
+
"currentSearchResult",
|
|
69
|
+
"currentSearch",
|
|
70
|
+
"searchEnabled",
|
|
71
|
+
"searchResults",
|
|
72
|
+
"searchLoading",
|
|
73
|
+
]),
|
|
74
|
+
searchBelowMinimum() {
|
|
75
|
+
return (
|
|
76
|
+
this.search &&
|
|
77
|
+
this.search.length > 0 &&
|
|
78
|
+
this.search.length < this.minSearchLength
|
|
79
|
+
);
|
|
80
|
+
},
|
|
81
|
+
currentCounter() {
|
|
82
|
+
return this.currentSearchResult != null && this.searchResults.length > 0
|
|
83
|
+
? this.currentSearchResult + 1
|
|
84
|
+
: 0;
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
watch: {
|
|
88
|
+
search(search) {
|
|
89
|
+
console.log("search", search);
|
|
90
|
+
this.$store.dispatch("display/setCurrentSearch", search);
|
|
91
|
+
if (search.length >= this.minSearchLength) {
|
|
92
|
+
this.$store.dispatch("display/startSearchLoading");
|
|
93
|
+
}
|
|
94
|
+
this.$store.dispatch("display/debounceSearch", search);
|
|
95
|
+
},
|
|
96
|
+
currentSearch(search) {
|
|
97
|
+
if (this.search !== search) {
|
|
98
|
+
this.search = search;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
searchEnabled(enabled) {
|
|
102
|
+
if (enabled) {
|
|
103
|
+
this.$nextTick(() => {
|
|
104
|
+
this.$refs.searchInput.focus();
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
mounted() {
|
|
110
|
+
if (this.currentSearch !== this.search) {
|
|
111
|
+
this.search = this.currentSearch;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
methods: {
|
|
115
|
+
focusSearchResult(n) {
|
|
116
|
+
this.$store.dispatch("display/setCurrentSearchResult", n);
|
|
117
|
+
},
|
|
118
|
+
closeSearch() {
|
|
119
|
+
this.$store.dispatch("display/resetSearch");
|
|
120
|
+
this.$store.dispatch("display/toggleSearch");
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style
|
|
127
|
+
scoped
|
|
128
|
+
lang="scss"
|
|
129
|
+
src="../../assets/scss/document_search_bar.scss"
|
|
130
|
+
></style>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
class="edit-btn btn"
|
|
33
33
|
@click="handleEdit"
|
|
34
34
|
>
|
|
35
|
-
{{ $t("
|
|
35
|
+
{{ $t("rename") }}
|
|
36
36
|
</div>
|
|
37
37
|
<div
|
|
38
38
|
v-if="showSaveBtn && !editMode"
|
|
@@ -56,6 +56,10 @@
|
|
|
56
56
|
<span v-else class="cloud-icon"><FileNameNotSaved /></span>
|
|
57
57
|
<span>{{ saved ? $t("saved") : $t("not_saved") }}</span>
|
|
58
58
|
</div>
|
|
59
|
+
|
|
60
|
+
<div v-if="detailsUrl" class="details-btn btn" @click="openDocumentDetails">
|
|
61
|
+
{{ $t("document_details") }}
|
|
62
|
+
</div>
|
|
59
63
|
</div>
|
|
60
64
|
</template>
|
|
61
65
|
|
|
@@ -97,8 +101,9 @@ export default {
|
|
|
97
101
|
"selectedDocument",
|
|
98
102
|
"publicView",
|
|
99
103
|
"recalculatingAnnotations",
|
|
104
|
+
"documentId",
|
|
100
105
|
]),
|
|
101
|
-
...mapState("display", ["optimalResolution"]),
|
|
106
|
+
...mapState("display", ["optimalResolution", "detailsUrl"]),
|
|
102
107
|
...mapState("edit", ["editMode"]),
|
|
103
108
|
...mapGetters("document", ["isDocumentReviewed"]),
|
|
104
109
|
textContent() {
|
|
@@ -229,6 +234,9 @@ export default {
|
|
|
229
234
|
contentNotEditable.blur();
|
|
230
235
|
}
|
|
231
236
|
},
|
|
237
|
+
openDocumentDetails() {
|
|
238
|
+
window.location.href = this.detailsUrl;
|
|
239
|
+
},
|
|
232
240
|
},
|
|
233
241
|
};
|
|
234
242
|
</script>
|
package/src/icons.js
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
faArrowLeft,
|
|
19
19
|
faArrowRight,
|
|
20
20
|
faDownload,
|
|
21
|
+
faSearch,
|
|
21
22
|
} from "@fortawesome/free-solid-svg-icons";
|
|
22
23
|
import { FontAwesomeIcon as Icons } from "@fortawesome/vue-fontawesome";
|
|
23
24
|
|
|
@@ -39,7 +40,8 @@ library.add(
|
|
|
39
40
|
faRepeat,
|
|
40
41
|
faArrowLeft,
|
|
41
42
|
faArrowRight,
|
|
42
|
-
faDownload
|
|
43
|
+
faDownload,
|
|
44
|
+
faSearch
|
|
43
45
|
);
|
|
44
46
|
|
|
45
47
|
export default Icons;
|
package/src/locales/de.json
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"set_status": "Setzen Sie bitte einen Status",
|
|
17
17
|
"status_error": "Wir konnten den Status nicht ändern. Bitte versuchen Sie es später erneut.",
|
|
18
18
|
"edit": "Bearbeiten",
|
|
19
|
+
"rename": "Umbenennen",
|
|
19
20
|
"save": "Speichern",
|
|
20
21
|
"autosaving": "Automatisches Speichern...",
|
|
21
22
|
"saved": "Gespeichert",
|
|
@@ -146,5 +147,10 @@
|
|
|
146
147
|
"translated_string_title": "Übersetzter Text",
|
|
147
148
|
"no_translated_string": "Es existiert noch keine Übersetzung.",
|
|
148
149
|
"add_translation": "Klicken Sie zum hinzufügen",
|
|
149
|
-
"edit_translation": "Zum Bearbeiten anklicken"
|
|
150
|
+
"edit_translation": "Zum Bearbeiten anklicken",
|
|
151
|
+
"search": "Suchen",
|
|
152
|
+
"no_results": "Keine Ergebnisse",
|
|
153
|
+
"search_below_minimum": "Mindestens 3 Zeichen",
|
|
154
|
+
"search_in_document": "Suche im Dokument",
|
|
155
|
+
"document_details": "Einzelheiten"
|
|
150
156
|
}
|
package/src/locales/en.json
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"set_status": "Set a status",
|
|
17
17
|
"status_error": "We couldn’t change the status. Please try again later.",
|
|
18
18
|
"edit": "Edit",
|
|
19
|
+
"rename": "Rename",
|
|
19
20
|
"save": "Save",
|
|
21
|
+
"details": "Details",
|
|
20
22
|
"autosaving": "Auto saving...",
|
|
21
23
|
"saved": "Saved",
|
|
22
24
|
"not_saved": "Could not save. Try again",
|
|
@@ -146,5 +148,10 @@
|
|
|
146
148
|
"translated_string_title": "Translated text",
|
|
147
149
|
"no_translated_string": "No translation exists yet.",
|
|
148
150
|
"add_translation": "Click to add one",
|
|
149
|
-
"edit_translation": "Click to edit"
|
|
151
|
+
"edit_translation": "Click to edit",
|
|
152
|
+
"search": "Search",
|
|
153
|
+
"no_results": "No results",
|
|
154
|
+
"search_below_minimum": "Minimum 3 characters",
|
|
155
|
+
"search_in_document": "Search document",
|
|
156
|
+
"document_details": "Details"
|
|
150
157
|
}
|
package/src/locales/es.json
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"set_status": "Establecer estado",
|
|
17
17
|
"status_error": "No ha sido posible cambiar el estado del documento. Por favor, inténtelo de nuevo más tarde.",
|
|
18
18
|
"edit": "Editar",
|
|
19
|
+
"rename": "Rebautizar",
|
|
19
20
|
"save": "Guardar",
|
|
20
21
|
"autosaving": "Auto guardando...",
|
|
21
22
|
"saved": "Guardado",
|
|
@@ -146,5 +147,10 @@
|
|
|
146
147
|
"translated_string_title": "Texto traducido",
|
|
147
148
|
"no_translated_string": "Aún no existe traducción.",
|
|
148
149
|
"add_translation": "Clic para agregar",
|
|
149
|
-
"edit_translation": "Clic para editar"
|
|
150
|
+
"edit_translation": "Clic para editar",
|
|
151
|
+
"search": "Buscar",
|
|
152
|
+
"no_results": "Sin resultados",
|
|
153
|
+
"search_below_minimum": "Mínimo 3 caracteres",
|
|
154
|
+
"search_in_document": "Buscar en documento",
|
|
155
|
+
"document_details": "Detalles"
|
|
150
156
|
}
|
package/src/store/display.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import BigNumber from "bignumber.js";
|
|
2
|
+
import myImports from "../api";
|
|
2
3
|
import {
|
|
3
4
|
PIXEL_RATIO,
|
|
4
5
|
VIEWPORT_RATIO,
|
|
5
6
|
MINIMUM_APP_WIDTH,
|
|
6
7
|
MINIMUM_OPTIMIZED_APP_WIDTH,
|
|
7
8
|
} from "../constants";
|
|
9
|
+
|
|
10
|
+
const HTTP = myImports.HTTP;
|
|
11
|
+
|
|
8
12
|
const debounce = (cb, duration) => {
|
|
9
13
|
let timer;
|
|
10
14
|
return (...args) => {
|
|
@@ -31,6 +35,12 @@ const state = {
|
|
|
31
35
|
pageChangedFromThumbnail: false,
|
|
32
36
|
showAnnSetTable: null,
|
|
33
37
|
showChooseLabelSetModal: null,
|
|
38
|
+
currentSearch: "",
|
|
39
|
+
searchEnabled: false,
|
|
40
|
+
searchResults: [],
|
|
41
|
+
searchLoading: false,
|
|
42
|
+
currentSearchResult: null,
|
|
43
|
+
detailsUrl: null,
|
|
34
44
|
};
|
|
35
45
|
|
|
36
46
|
const getters = {
|
|
@@ -54,6 +64,28 @@ const getters = {
|
|
|
54
64
|
return [previousPage, state.currentPage, nextPage];
|
|
55
65
|
},
|
|
56
66
|
|
|
67
|
+
searchResultsForPage: (state, getters) => (pageNumber) => {
|
|
68
|
+
if (!state.searchEnabled || state.searchResults.length < 1) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return state.searchResults.filter((r) => r.page_index + 1 === pageNumber);
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
currentSearchResultForPage: (state) => (pageNumber) => {
|
|
76
|
+
if (!state.searchEnabled || state.searchResults.length < 1) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const currentResult = state.searchResults[state.currentSearchResult];
|
|
81
|
+
|
|
82
|
+
if (!currentResult || currentResult.page_index !== pageNumber - 1) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return currentResult;
|
|
87
|
+
},
|
|
88
|
+
|
|
57
89
|
/**
|
|
58
90
|
* The proportion between the original size of the page and the
|
|
59
91
|
* image rendering.
|
|
@@ -259,6 +291,66 @@ const actions = {
|
|
|
259
291
|
setPageChangedFromThumbnail: ({ commit }, value) => {
|
|
260
292
|
commit("SET_PAGE_CHANGED_FROM_THUMBNAIL", value);
|
|
261
293
|
},
|
|
294
|
+
|
|
295
|
+
setDetailsUrl: ({ commit }, value) => {
|
|
296
|
+
commit("SET_DETAILS_URL", value);
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
debounceSearch: debounce(({ commit, dispatch }, query) => {
|
|
300
|
+
dispatch("search", query);
|
|
301
|
+
}, 300),
|
|
302
|
+
|
|
303
|
+
startSearchLoading({ commit }) {
|
|
304
|
+
commit("SET_SEARCH_LOADING", true);
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
search({ commit, rootState }, query) {
|
|
308
|
+
// only allow queries that are at least 3 characters long
|
|
309
|
+
if (query.length >= 3) {
|
|
310
|
+
return HTTP.post(`documents/${rootState.document.documentId}/search/`, {
|
|
311
|
+
q: query,
|
|
312
|
+
}).then((response) => {
|
|
313
|
+
commit("SET_SEARCH_RESULTS", response.data.span);
|
|
314
|
+
commit("SET_SEARCH_LOADING", false);
|
|
315
|
+
});
|
|
316
|
+
} else {
|
|
317
|
+
commit("SET_SEARCH_RESULTS", []);
|
|
318
|
+
commit("SET_SEARCH_LOADING", false);
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
resetSearch({ commit }) {
|
|
323
|
+
commit("SET_CURRENT_SEARCH", "");
|
|
324
|
+
commit("SET_SEARCH_RESULTS", []);
|
|
325
|
+
commit("SET_SEARCH_LOADING", false);
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
toggleSearch({ commit }) {
|
|
329
|
+
commit("TOGGLE_SEARCH");
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
enableSearch({ commit }, toEnable) {
|
|
333
|
+
commit("ENABLE_SEARCH", toEnable);
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
setCurrentSearch({ commit }, currentSearch) {
|
|
337
|
+
commit("SET_CURRENT_SEARCH", currentSearch);
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
setCurrentSearchResult({ commit, state }, n) {
|
|
341
|
+
let newSearchResult = state.currentSearchResult + n;
|
|
342
|
+
const searchResultsMaxIndex = state.searchResults.length - 1;
|
|
343
|
+
|
|
344
|
+
if (newSearchResult > searchResultsMaxIndex) {
|
|
345
|
+
// once we're at the end of the results, start again
|
|
346
|
+
newSearchResult = 0;
|
|
347
|
+
} else if (newSearchResult < 0) {
|
|
348
|
+
// once we're at the beginning of the results, go to the end
|
|
349
|
+
newSearchResult = searchResultsMaxIndex;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
commit("SET_CURRENT_SEARCH_RESULT", newSearchResult);
|
|
353
|
+
},
|
|
262
354
|
};
|
|
263
355
|
|
|
264
356
|
const mutations = {
|
|
@@ -303,6 +395,28 @@ const mutations = {
|
|
|
303
395
|
SET_SHOW_CHOOSE_LABEL_SET_MODAL: (state, options) => {
|
|
304
396
|
state.showChooseLabelSetModal = options;
|
|
305
397
|
},
|
|
398
|
+
SET_SEARCH_RESULTS: (state, searchResults) => {
|
|
399
|
+
state.currentSearchResult = 0;
|
|
400
|
+
state.searchResults = searchResults;
|
|
401
|
+
},
|
|
402
|
+
SET_SEARCH_LOADING: (state, loading) => {
|
|
403
|
+
state.searchLoading = loading;
|
|
404
|
+
},
|
|
405
|
+
TOGGLE_SEARCH: (state) => {
|
|
406
|
+
state.searchEnabled = !state.searchEnabled;
|
|
407
|
+
},
|
|
408
|
+
ENABLE_SEARCH: (state, toEnable) => {
|
|
409
|
+
state.searchEnabled = toEnable;
|
|
410
|
+
},
|
|
411
|
+
SET_CURRENT_SEARCH: (state, currentSearch) => {
|
|
412
|
+
state.currentSearch = currentSearch;
|
|
413
|
+
},
|
|
414
|
+
SET_CURRENT_SEARCH_RESULT: (state, n) => {
|
|
415
|
+
state.currentSearchResult = n;
|
|
416
|
+
},
|
|
417
|
+
SET_DETAILS_URL: (state, value) => {
|
|
418
|
+
state.detailsUrl = value;
|
|
419
|
+
},
|
|
306
420
|
};
|
|
307
421
|
|
|
308
422
|
export default {
|
package/src/store/document.js
CHANGED
|
@@ -663,8 +663,6 @@ const getters = {
|
|
|
663
663
|
return label.annotations;
|
|
664
664
|
});
|
|
665
665
|
|
|
666
|
-
console.log(annotations);
|
|
667
|
-
|
|
668
666
|
return annotations.length === 0 ? true : false;
|
|
669
667
|
},
|
|
670
668
|
};
|
|
@@ -672,6 +670,7 @@ const getters = {
|
|
|
672
670
|
const actions = {
|
|
673
671
|
startLoading: ({ commit }) => {
|
|
674
672
|
commit("SET_LOADING", true);
|
|
673
|
+
commit("display/ENABLE_SEARCH", false, { root: true });
|
|
675
674
|
},
|
|
676
675
|
endLoading: ({ commit }) => {
|
|
677
676
|
commit("SET_LOADING", false);
|