Skip to content

Commit 7a8655b

Browse files
authored
Merge pull request doccano#328 from CatalystCode/enhancement/long-document-annotation-improvements
Enhancement/long document annotation improvements
2 parents 8a90df9 + 9bdedf9 commit 7a8655b

File tree

6 files changed

+136
-27
lines changed

6 files changed

+136
-27
lines changed

app/app/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216
'rest_framework.authentication.TokenAuthentication',
217217
),
218218
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
219-
'PAGE_SIZE': 5,
219+
'PAGE_SIZE': env.int('DOCCANO_PAGE_SIZE', default=5),
220220
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
221221
'SEARCH_PARAM': 'q',
222222
'DEFAULT_RENDERER_CLASSES': (

app/server/static/assets/css/annotation.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ body {
1212
border-right: 1px solid #DEDEDE;
1313
}
1414

15+
.scrollable {
16+
max-height: 60vh;
17+
overflow-y: auto;
18+
}
19+
20+
.sidebar-scrollable {
21+
max-height: 100vh;
22+
overflow-y: auto;
23+
overflow-x: hidden;
24+
}
25+
1526
.messages {
1627
display: block;
1728
background-color: #fff;

app/server/static/components/annotation.pug

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ div.columns(v-cloak="")
5353
| Completed
5454

5555
div.main.pt0.pb0.pr20.pl20
56-
span About {{ count }} results
56+
span About {{ count }} results (page {{ paginationPage }} of {{ paginationPages }})
5757

58-
div.main
58+
div.main.sidebar-scrollable
5959
a.item(
6060
v-for="(doc, index) in docs"
6161
v-bind:class="{ active: index == pageNumber }"
@@ -141,22 +141,41 @@ div.columns(v-cloak="")
141141
preview(v-bind:url="documentMetadata.documentSourceUrl")
142142

143143
div.level.mt30
144-
a.button.level-left(
145-
v-shortkey="{ prev1: ['ctrl', 'p'], prev2: ['arrowup'], prev3: ['arrowleft'] }"
146-
v-on:click="prevPage"
147-
v-on:shortkey="prevPage"
148-
)
149-
span.icon
150-
i.fas.fa-chevron-left
151-
span Prev
152-
153-
span.button.level-center.is-static {{ offset + pageNumber + 1 }} / {{ count }}
154-
155-
a.button.level-right(
156-
v-shortkey="{ next1: ['ctrl', 'n'], next2: ['arrowdown'], next3: ['arrowright'] }"
157-
v-on:click="nextPage"
158-
v-on:shortkey="nextPage"
159-
)
160-
span Next
161-
span.icon
162-
i.fas.fa-chevron-right
144+
div.level-left
145+
div.buttons
146+
a.button(
147+
v-shortkey="{ prev1: ['shift', 'ctrl', 'p'], prev2: ['shift', 'arrowup'], prev3: ['shift', 'arrowleft'] }"
148+
v-on:click="prevPagination"
149+
v-on:shortkey="prevPagination"
150+
)
151+
span.icon.tooltip(data-tooltip="Previous page")
152+
i.fas.fa-arrow-left
153+
154+
a.button(
155+
v-shortkey="{ prev1: ['ctrl', 'p'], prev2: ['arrowup'], prev3: ['arrowleft'] }"
156+
v-on:click="prevPage"
157+
v-on:shortkey="prevPage"
158+
)
159+
span.icon.tooltip(data-tooltip="Previous document")
160+
i.fas.fa-chevron-left
161+
162+
div.level-center
163+
span.button.is-static {{ offset + pageNumber + 1 }} / {{ count }}
164+
165+
div.level-right
166+
div.buttons
167+
a.button(
168+
v-shortkey="{ next1: ['ctrl', 'n'], next2: ['arrowdown'], next3: ['arrowright'] }"
169+
v-on:click="nextPage"
170+
v-on:shortkey="nextPage"
171+
)
172+
span.icon.tooltip(data-tooltip="Next document")
173+
i.fas.fa-chevron-right
174+
175+
a.button(
176+
v-shortkey="{ next1: ['shift', 'ctrl', 'n'], next2: ['shift', 'arrowdown'], next3: ['shift', 'arrowright'] }"
177+
v-on:click="nextPagination"
178+
v-on:shortkey="nextPagination"
179+
)
180+
span.icon.tooltip(data-tooltip="Next page")
181+
i.fas.fa-arrow-right

app/server/static/components/annotationMixin.js

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ const getOffsetFromUrl = (url) => {
1313
return parseInt(offsetMatch[1], 10);
1414
};
1515

16+
const removeHost = (url) => {
17+
if (!url) {
18+
return url;
19+
}
20+
21+
const hostMatch = url.match(/^https?:\/\/[^/]*\/(.*)$/);
22+
if (hostMatch == null) {
23+
return url;
24+
}
25+
26+
return `${window.location.origin}/${hostMatch[1]}`;
27+
};
28+
1629
const storeOffsetInUrl = (offset) => {
1730
let href = window.location.href;
1831

@@ -36,6 +49,28 @@ const storeOffsetInUrl = (offset) => {
3649
window.location.href = href;
3750
};
3851

52+
const getLimitFromUrl = (url, prevLimit) => {
53+
try {
54+
const limitMatch = url.match(/[?#].*limit=(\d+)/);
55+
56+
return parseInt(limitMatch[1], 10);
57+
} catch (err) {
58+
return prevLimit;
59+
}
60+
};
61+
62+
const getSidebarTotal = (count, limit) => (
63+
count !== 0 && limit !== 0
64+
? Math.ceil(count / limit)
65+
: 0
66+
);
67+
68+
const getSidebarPage = (offset, limit) => (
69+
limit !== 0
70+
? Math.ceil(offset / limit) + 1
71+
: 0
72+
);
73+
3974
export default {
4075
components: { VueJsonPretty, Preview },
4176

@@ -53,13 +88,23 @@ export default {
5388
offset: getOffsetFromUrl(window.location.href),
5489
picked: 'all',
5590
count: 0,
91+
prevLimit: 0,
92+
paginationPages: 0,
93+
paginationPage: 0,
5694
isSuperuser: false,
5795
isMetadataActive: false,
5896
isAnnotationGuidelineActive: false,
5997
};
6098
},
6199

62100
methods: {
101+
resetScrollbar() {
102+
const textbox = this.$refs.textbox;
103+
if (textbox) {
104+
textbox.scrollTop = 0;
105+
}
106+
},
107+
63108
async nextPage() {
64109
this.pageNumber += 1;
65110
if (this.pageNumber === this.docs.length) {
@@ -70,6 +115,8 @@ export default {
70115
} else {
71116
this.pageNumber = this.docs.length - 1;
72117
}
118+
} else {
119+
this.resetScrollbar();
73120
}
74121
},
75122

@@ -83,17 +130,49 @@ export default {
83130
} else {
84131
this.pageNumber = 0;
85132
}
133+
} else {
134+
this.resetScrollbar();
135+
}
136+
},
137+
138+
async nextPagination() {
139+
if (this.next) {
140+
this.url = this.next;
141+
await this.search();
142+
this.pageNumber = 0;
143+
} else {
144+
this.pageNumber = this.docs.length - 1;
86145
}
146+
this.resetScrollbar();
147+
},
148+
149+
async prevPagination() {
150+
if (this.prev) {
151+
this.url = this.prev;
152+
await this.search();
153+
this.pageNumber = this.docs.length - this.limit;
154+
} else {
155+
this.pageNumber = 0;
156+
}
157+
this.resetScrollbar();
87158
},
88159

89160
async search() {
90161
await HTTP.get(this.url).then((response) => {
91162
this.docs = response.data.results;
92-
this.next = response.data.next;
93-
this.prev = response.data.previous;
163+
this.next = removeHost(response.data.next);
164+
this.prev = removeHost(response.data.previous);
94165
this.count = response.data.count;
95166
this.annotations = this.docs.map(doc => doc.annotations);
96167
this.offset = getOffsetFromUrl(this.url);
168+
this.prevLimit = this.limit;
169+
if (this.next || this.prevLimit) {
170+
this.limit = getLimitFromUrl(this.next, this.prevLimit);
171+
} else {
172+
this.limit = this.count;
173+
}
174+
this.paginationPages = getSidebarTotal(this.count, this.limit);
175+
this.paginationPage = getSidebarPage(this.offset, this.limit);
97176
});
98177
},
99178

app/server/static/components/document_classification.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ block annotation-area
3333
button.delete.is-small(v-on:click="removeLabel(annotation)")
3434

3535
hr
36-
div.content(v-if="docs[pageNumber]")
37-
span.text {{ docs[pageNumber].text }}
36+
div.content
37+
div.text.scrollable(ref="textbox", v-if="docs[pageNumber]") {{ docs[pageNumber].text }}
3838
</template>
3939

4040
<style scoped>

app/server/static/components/sequence_labeling.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ block annotation-area
2121
kbd {{ shortcutKey(label) | simpleShortcut }}
2222

2323
div.card-content
24-
div.content(v-if="docs[pageNumber] && annotations[pageNumber]")
24+
div.content.scrollable(v-if="docs[pageNumber] && annotations[pageNumber]", ref="textbox")
2525
annotator(
2626
v-bind:labels="labels"
2727
v-bind:entity-positions="annotations[pageNumber]"

0 commit comments

Comments
 (0)