Projekt

Obecné

Profil

Stáhnout (9.19 KB) Statistiky
| Větev: | Tag: | Revize:
1
import React, { createContext, useEffect, useState } from 'react';
2
import { AnnotationInfo, ETagType, SubTagInfo, TagInfo, TagInstanceInfo } from '../api';
3
import { Tag } from '../components/types/tag';
4
import { annotationController, userController } from '../controllers';
5
import { GetSelectionInfo } from '../utils/selectionUtils';
6
import { ShowConfirmDelete, ShowToast } from '../utils/alerts';
7

    
8
/**
9
 * Interface of an annotation context provider.
10
 */
11
interface IAnnotationContextProvider {
12
    /**
13
     * Tags managed by the context.
14
     */
15
    tags: TagInstanceInfo[] | null;
16

    
17
    /**
18
     * Submitting boolean
19
     */
20
    submitting: boolean;
21

    
22
    /**
23
     * Sets new tags.
24
     * @param newTags An array of new tags.
25
     */
26
    setTags: (newTags: TagInstanceInfo[] | null) => void;
27

    
28
    /**
29
     * Adds occurrence to an annotation.
30
     * @param tag Tag whose occurrence should be added.
31
     */
32
    addOccurrence: (tag: Tag) => void;
33

    
34
    /**
35
     * Changes visibility of an annotation.
36
     * @param tag Tag whose visibility should be changed.
37
     */
38
    changeVisibility: (tag: Tag) => void;
39

    
40
    /**
41
     * Deletes an occurrence of an annotation.
42
     * @param occurrence Occurrence that should be deleted.
43
     */
44
    deleteOccurrence: (occurrence: TagInstanceInfo) => void;
45

    
46
    /**
47
     * Changes a position of an occurrence of an annotation.
48
     * @param occurrence Occurrence whose position should be changed.
49
     * @param newValue New value of the position.
50
     */
51
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => void;
52

    
53
    /**
54
     * Changes a length of an occurrence of an annotation.
55
     * @param occurrence Occurrence whose length should be changed.
56
     * @param newValue New value of the length.
57
     */
58
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => void;
59

    
60
    annotation: AnnotationInfo | null;
61
    mappedTags: Tag[] | null;
62
    refreshAnnotation: () => void;
63

    
64
    markSelectedText: (
65
        tagId: string,
66
        subtagId: string | null,
67
        instanceID: string | null
68
    ) => void;
69
}
70

    
71
/**
72
 * The annotation context that manages active annotations.
73
 */
74
export const AnnotationContext = createContext<IAnnotationContextProvider>({
75
    /**
76
     * Default tags.
77
     */
78
    tags: null,
79

    
80
    /**
81
     * Submitting boolean
82
     */
83
    submitting: false,
84

    
85
    /**
86
     * Default implementation of setTags method.
87
     * @param v Array of new tags.
88
     */
89
    setTags: (v) => {
90
        return;
91
    },
92

    
93
    /**
94
     * Default implementation of addOccurrence method.
95
     * @param tag The tag with new occurrence.
96
     */
97
    addOccurrence: (tag: Tag) => {
98
        return;
99
    },
100

    
101
    /**
102
     * Default implementation of changeVisibility method.
103
     * @param tag The tag whose visibility should be changed.
104
     */
105
    changeVisibility: (tag: Tag) => {
106
        return;
107
    },
108

    
109
    /**
110
     * Default implementation of deleteOccurrence method.
111
     * @param occurrence Occurrence that should be deleted.
112
     */
113
    deleteOccurrence: (occurrence: TagInstanceInfo) => {
114
        return;
115
    },
116

    
117
    /**
118
     * Default implementation of changePosition method.
119
     * @param occurrence Occurrence whose position should be changed.
120
     * @param newValue A new position.
121
     */
122
    changePosition: (occurrence: TagInstanceInfo, newValue: number) => {
123
        return;
124
    },
125

    
126
    /**
127
     * Default implementation of changeLength method.
128
     * @param occurrence Occurrence whose length should be changed.
129
     * @param newValue A new length.
130
     */
131
    changeLength: (occurrence: TagInstanceInfo, newValue: number) => {
132
        return;
133
    },
134

    
135
    annotation: null,
136
    mappedTags: null,
137
    refreshAnnotation: () => {
138
        return;
139
    },
140

    
141
    markSelectedText: () => {
142
        return;
143
    },
144
});
145

    
146
/**
147
 * Provider of the annotation context.
148
 * @param props Children that should have access to the annotation context.
149
 * @returns Prepared html of the provider.
150
 */
151
const AnnotationProvider = (props: {
152
    children: React.ReactNode;
153
    annotationId: string;
154
}) => {
155
    const [annotation, setAnnotation] = useState<AnnotationInfo | null>(null);
156

    
157
    /**
158
     * Tags managed by the context.
159
     */
160
    const [tags, setTags] = useState<TagInstanceInfo[] | null>(null);
161

    
162
    const [mappedTags, setMappedTags] = useState<Tag[] | null>(null);
163

    
164
    const [submitting, setSubmitting] = useState(false);
165

    
166
    async function markSelectedText(
167
        tagId: string,
168
        subtagId: string | null,
169
        instanceId: string | null
170
    ) {
171
        setSubmitting(true);
172
        if (!annotation) {
173
            console.log('annotation not found');
174
            return;
175
        }
176

    
177
        const selectionInfo = GetSelectionInfo(annotation);
178
        if (!selectionInfo) {
179
            console.log(
180
                'not able to continue, selection processing not completed successfully'
181
            );
182
            ShowToast('Není označen žádný text pro přidělení značky', 'warning');
183
            setSubmitting(false);
184
            return;
185
        }
186

    
187
        const id = subtagId ?? tagId;
188
        const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
189
        const res = await annotationController
190
            .annotationAnnotationIdPost(props.annotationId, {
191
                id: id,
192
                instanceId,
193
                type,
194
                position: selectionInfo.startPositionOriginalDocument,
195
                length: selectionInfo.selectionLengthOriginalDocument,
196
            })
197
            .catch((e) =>
198
                ShowToast('Tato část textu je již touto značkou anotována', 'warning')
199
            );
200

    
201
        await refreshAnnotation();
202
    }
203

    
204
    /**
205
     * Default implementation of addOccurrence method.
206
     * @param tag The tag with new occurrence.
207
     */
208
    const addOccurrence = async (tag: Tag) => {
209
        await markSelectedText(tag.tagId, tag.subtagId ?? null, tag.instanceId);
210
    };
211

    
212
    /**
213
     * Changes visibility of an annotation.
214
     * @param tag Tag whose visibility should be changed.
215
     */
216
    const changeVisibility = (tag: Tag) => {
217
        //TODO: Implement method (should use objects from server API)
218
    };
219

    
220
    /**
221
     * Deletes an occurrence of an annotation.
222
     * @param occurrence Occurrence that should be deleted.
223
     */
224
    const deleteOccurrence = async (occurrence: TagInstanceInfo) => {
225
        if (!occurrence.occurenceId) {
226
            console.log('invalid occurrence');
227
            return;
228
        }
229

    
230
        ShowConfirmDelete(() => {
231
            annotationController
232
                .annotationAnnotationIdOccurenceIdDelete(
233
                    props.annotationId,
234
                    occurrence.occurenceId ?? ''
235
                )
236
                .then(() => refreshAnnotation());
237
        }, 'značku');
238
    };
239

    
240
    /**
241
     * Changes a position of an occurrence of an annotation.
242
     * @param occurrence Occurrence whose position should be changed.
243
     * @param newValue New value of the position.
244
     */
245
    const changePosition = (occurrence: TagInstanceInfo, newValue: number) => {
246
        //TODO: Implement method (should use objects from server API)
247
    };
248

    
249
    /**
250
     * Changes a length of an occurrence of an annotation.
251
     * @param occurrence Occurrence whose length should be changed.
252
     * @param newValue New value of the length.
253
     */
254
    const changeLength = (occurrence: TagInstanceInfo, newValue: number) => {
255
        //TODO: Implement method (should use objects from server API)
256
    };
257

    
258
    const remapAnnotations = (data: AnnotationInfo) => {
259
        let map = new Map<string, Tag>();
260
        data.tagInstances?.forEach((tagInstance) => {
261
            if (map.has(tagInstance.instance ?? '-')) {
262
                let tag = map.get(tagInstance.instance ?? '-');
263
                tag!.occurrences = [...tag!.occurrences, tagInstance];
264
            } else {
265
                map.set(tagInstance.instance ?? '-', {
266
                    tagName: tagInstance.tagName ?? '',
267
                    subtagName: tagInstance.subTagName ?? null,
268
                    category: tagInstance.tagCategoryName ?? '',
269
                    visible: true,
270
                    occurrences: [tagInstance],
271
                    tagId: tagInstance.tagId ?? '',
272
                    instanceId: tagInstance.instance ?? '',
273
                    subtagId: tagInstance.subTagId ?? null,
274
                });
275
            }
276
        });
277

    
278
        setMappedTags(Array.from(map.values()));
279
    };
280

    
281
    async function refreshAnnotation() {
282
        const data = await annotationController.annotationAnnotationIdGet(
283
            props.annotationId
284
        );
285

    
286
        remapAnnotations(data.data);
287
        setAnnotation(data.data ?? null);
288
        setSubmitting(false);
289
    }
290

    
291
    /**
292
     * Initializes the context.
293
     */
294
    useEffect(() => {
295
        refreshAnnotation();
296
    }, [props.annotationId]);
297

    
298
    return (
299
        <AnnotationContext.Provider
300
            value={{
301
                tags,
302
                submitting,
303
                setTags,
304
                addOccurrence,
305
                changeVisibility,
306
                deleteOccurrence,
307
                changeLength,
308
                changePosition,
309
                refreshAnnotation,
310
                annotation,
311
                mappedTags,
312
                markSelectedText,
313
            }}
314
        >
315
            {props.children}
316
        </AnnotationContext.Provider>
317
    );
318
};
319

    
320
export default AnnotationProvider;
(1-1/3)